zoukankan      html  css  js  c++  java
  • 浅谈JavaScript的作用域

      前段时间学了下JavaScript作用域,这个东西在JavaScript非常重要,也是JavaScript很基础的东西,正如少林里面基础武功,有了基础,才能学绝世武功。

      作用域的作用是啥?一套设计良好的规则来存储变量,并且之后可以方便的找到这些变量。

      就JavaScript里面的作用域来说,我总结有这么几个关键词:

      1. 词法作用域

      2. 函数作用域

      3. 块级作用域

      4. 闭包

      5. 提升

      好吧,我脑海里面能想到的就这么多了,不够的,也可以有朋友指出来,接下来,我一个一个过下这些词。

      一、词法作用域

      顾名思义,针对于词法的作用域,这是什么鬼?词法有作用域吗?难道不是只有函数作用域吗?有啥子用啊?  

      其实,词法作用域非常有用,它是针对词法的,没错就是词法,那什么是词法?

      JavaScript是一面动态语言,也就是先编译,再运行,在编译的第一个工作阶段叫词法化。词法化的时候,会对源代码中的标识符(变量和函数)进行检查,如果有状态的解析过程,还会赋予单词语意。

      词法作用域就是定义在词法阶段的作用域,词法作用域是有你在写代码时将变量和块作用域写在哪里来决定的。

      引擎凭什么能找到变量?是根据什么来查找的呢?

      举个例子:

    function test() {
    	var a = 3;
    	console.log(a);
    }
    
    test(); // output 3;
    

      这个例子相当简单,就拿这个a变量来说,test函数内,是局部变量,a的词法作用域就是test函数体内,如果在函数体外再调用a变量,比如:

    function test() {
    	var a = 3;
    	console.log(a);
    }
    
    test();
    
    cosole.log(a);

      会抛出引用异常的错误(ReferenceError)。

      通过上面这个例子,只是简单的说明了下变量的词法作用域。在词法分析中,任何标识符,都有词法作用域,引擎就通过作用域来查找标识符的,会从内到外层作用域查找,直到找到第一个匹配的标识符停止,如果没找到,这会抛出引用异常的错误。

      二、函数作用域

      函数作用域,相信学过编程语言(比如C、C++等),对这个应该不陌生,每个函数都有自己的作用域,也就是函数作用域,这里就跳过了。

      三、块级作用域

      什么是块级作用域?块级作用域,就是用一对{}包裹起来的作用域,比如if语句,else语句,还有for语句等等。但是一般来说JavaScript里面是没有块级作用域这个概念的,但是,也有特例,在es3中开始,就有一个块级作用域的例子。

      就是try catch,看下面例子:

    try	{
    	undefined(); // 强行出错
    } catch(e) {
    	console.log(e);
    } 
    

      如果没有块级作用域的概念,那么这个e应该是全局的,在外面也可以访问,如下:

    try	{
    	undefined(); // 强行出错
    } catch(e) {
    	console.log(e);
    } 
    
    console.log(e);
    

      实际上,这样会抛出引用异常,e变量仅在catch中有效,这说明try catch是支持块级作用域的。

      其实在ES6中,JavaScript已经可以支持块级作用域了,比如let关键字。

      四、闭包

      闭包是什么?闭包和函数有什么关系?

      其实闭包我们平时很常用,只是大家没注意到罢了,闭包是函数运行时能访问其函数作用域之外的上下文环境,是一个动态的概念。如下:

    function test() {
    
    	var a = 3;
    
    	function btest() {
    		// a变量为btest函数之外的变量
    		console.log(a);
    	}
    
    	btest(); // 通过闭包调用a
    }
    
    test(); 
    

      闭包是函数的代码在运行过程中的一个动态环境,函数可以理解为静态的代码。在这个动态环境内,如果函数只访问函数作用域里面变量(当然全局变量也算),那么是不存在闭包的;但是这个动态环境,还能访问其函数作用外的其他变量(也除了全局变量),那么有闭包了。

      五、提升

      提升什么?其实呢,就是浏览器在预编译的时候,会把所有的声明提前,其中包括变量声明和函数声明,如下:

    test();
    
    function test() {
    
    	var a = 3;
    	
    	console.log(a);
    }
    

      上面的代码演示,就是函数提升,注意,函数表达式不会提升,如下:

    test();
    
    var tset = function() {
    
    	var a = 3;
    	
    	console.log(a);
    }
    

      这会抛出引用异常的错误!

    a = 3;
    
    var a;
    
    console.log(a);
    

      上面的代码是变量声明提升,切记是声明提升,赋值操作并不提升。

      总结:JavaScript使用作用域链来实现闭包,作用域链由执行环境维护,JavaScript中所有的标识符都是通过作用域链来查找值的。

      作用域这块,现在已经入门了,离精通还差很多,还需要多学多练,早日把这块搞透,学习正如逆水行舟,真是因为难,才更需要搞懂,如果只做力所能及的事,将永远得不到提升!

  • 相关阅读:
    Asp.NET 4.0 ajax实例DataView 模板编程1
    ASP.NET 4.0 Ajax 实例DataView模板编程 DEMO 下载
    部分东北话、北京话
    .NET 培训课程解析(一)
    ASP.NET 4.0 Ajax 实例DataView模板编程2
    ASP.NET Web Game 架构设计1服务器基本结构
    ASP.NET Web Game 构架设计2数据库设计
    TFS2008 基本安装
    Linux上Oracle 11g安装步骤图解
    plsql developer远程连接oracle数据库
  • 原文地址:https://www.cnblogs.com/pijiaxiang/p/5245225.html
Copyright © 2011-2022 走看看