块级作用域与函数作用域

函数作用域:变量在定义的环境中以及嵌套的子函数中处处可见;
块级作用域:变量在离开定义的块级代码后立即被回收。

函数作用域

在ES6之前,js的作用域只有两种:函数作用域和全局作用域。使用var声明的变量,都存在变量提升的过程。

    console.log(a); //undefined
    console.log(c); //undefined
    console.log(d); //function d() {}
    console.log(b); //报错,b is not defined
    
    var a = 0;
    let b = 1;
    var c = function () {

    };
    function d() {
        
    }

由此可见使用let声明的变量不会提升,函数声明会完全提升。上面的代码等价于:

    var a;
    var c;
    function d() {}
    
    console.log(a);
    console.log(c);
    console.log(d);
    console.log(b);
    
    a = 0;
    let b = 1;
    c = function () {

    };
  

块级作用域

ES6中定义了块级作用域,使用let声明的变量只能在块级作用域里访问,有“暂时性死区”的特性(也就是说声明前不可用)。

'use strict';
var test = 1;
function func(){
    //打印test的值
    console.log(test); //报错, test is not defined.
    let test = 2;
};
func();

函数会从自身的活动对象开始,一层层向上寻找自己所需的变量,该函数在寻找test时发现,自己的作用域里声明了let,它就不会再往上找,而let在声明之前是不可用的,所以就会报错。

自己的理解

虽然《js高程》里说,ES6之前,js没有块级作用域。但我认为with语句和try-catch语句有类似于块级作用域的地方。

    var l = {
        x: 0,
        y: 1
    };

    function f() {
        with(l) {
            console.log(x); //0
            var a = 1;
        }

	cosnole.log(a); //1
        console.log(x); //报错,x is not defined.
    }

    f();

函数f利用with语句扩展了自己的作用域链,相当于with语句开始执行时,参数l中所包含的所有变量都被临时加入到该函数的活动对象中,等到语句执行结束,它们就会被移除。它们只在with语句块中有效。还有一点就是,with语句中声明的变量a,使用var声明的变量会自动被添加到离它最近的环境中,离a最近的环境就是函数的局部环境,所以a就会被添加到函数的活动对象中,即使在with语句之外也能被访问。

你可能感兴趣的:(JavaScript)