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中所有的标识符都是通过作用域链来查找值的。

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

  • 相关阅读:
    为了实现在线库的复杂查询,你还在双写吗?
    双11核心系统100%上云 !阿里数据库处理峰值远超传统厂商
    每秒8700万次!双11数据库峰值新纪录背后的关键力量
    最强CP!阿里云联手支付宝小程序如何助力双11?
    .net IAsyncResult 异步操作
    .net Reflection(反射)- 二
    .net Reflection(反射)- 一
    .net 空接合操作符 ??
    .net 基元类型,引用类型和值类型
    .net List<T>
  • 原文地址:https://www.cnblogs.com/pijiaxiang/p/5245225.html
Copyright © 2011-2022 走看看