JavaScript中的执行环境、作用域链和闭包详解(内附《JavaScript高级程序设计》书籍)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/IT_10/article/details/82017973

执行环境

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个函数都有自己的执行环境。执行环境中定义的变量或函数保存在变量对象中
例如,在web浏览器中,全局执行环境被认为是windows对象,因此所有全局变量和函数都是作为 window 对象的属性和方法创建的,比如我们调用windows.load()方法。
某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或浏览器——时才会被销毁)。

作用域链

当代码在环境中执行时,会创建变量对象的一个作用域链
作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。这个指针列表的第0个位置始终都是当前执行的代码所在环境的变量对象,下一个位置指向包含环境,即假如该函数的外层还定义了一个函数,则这个位置指向这个外层函数的变量对象,在下一个位置指向下一个包含环境,这样一直延续到作用域的的最后一个位置——–全局执行环境。标识符的解析就是通过这个作用域链一级一级查找标识符的过程,所以最开始说作用域链的作用就是保证对执行环境有权访问的所有变量和函数的有序访问。
例1

var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、 anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但不能访问 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();

例2:

function compare(value1, value2){
    if (value1 < value2){
        return -1;
    } else if (value1 > value2){
        return 1;
    } else {
        return 0;
    }
}
var result = compare(5, 10);

compare()函数执行时的作用域链:
这里写图片描述

注:函数的执行环境成为活动对象,活动对象的第一位始终是arguments变量(是一个类数组)

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。
创建闭包的常见方式,就是在一个函数A内部创建另一个函数B。而函数B能够访问到函数A中创建的变量,就是通过作用域链实现的。
例3:

//createComparisonFunction函数的作用通过传入的对象的不同的属性名从而比较该属性值的大小。
function createComparisonFunction(propertyName) {
    return function(object1, object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
            if (value1 < value2){
                return -1;
            } else if (value1 > value2){
                return 1;
            } else {
                return 0;
            }
    };
}

带有闭包的作用域链:
这里写图片描述
例4:

    function createFunction(){
        var result=new Array();

        for(var i=0;i<10;i++){
            result[i]=function(){
                return i;
            }
        }
        return result;
    }

    var res=createFunction();
    for(var i=0;i<10;i++){
        console.log(res[i]());
    }

这段代码我们预期将0到9放入result数组中,但解决却打印出来十个10,这是为什么?因为闭包只能取得包含函数中任何变量的最后一个值,即res[i]的作用域链中有个指针指向包含函数createFunction的活动对象,而此时该活动对象中i的值已经为10。
修改以上代码如下即可得到预期结果:

function createFunction(){
        var result=new Array();

        for(var i=0;i<10;i++){
            result[i]=function(num){
                return function(){
                    return num;
                }
            }(i); 
        }
        return result;
    }
    var res=createFunction();
    for(var i=0;i<10;i++){
        console.log(res[i]());
    }

注:以上内容参照《JavaScript高级程序设计》一书,在这里将此书的高清电子版分享给大家。
链接:https://pan.baidu.com/s/1EWXKDMnhR2HkyoNxxitLxw 密码:uhs4

猜你喜欢

转载自blog.csdn.net/IT_10/article/details/82017973