node.js - JavaScript闭包中令人困惑的一个奇怪问题

查看:142
本文介绍了node.js - JavaScript闭包中令人困惑的一个奇怪问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

例1:

var obj = new Object();
var events = {m1: 'clicked', m2: 'changed'};

for (var e in events) {
    (function() {
        var aValue = e;
        obj[e] = function() {
            //var aValue = e;
            console.log(events[aValue]);
        };
    }());
};

console.log(obj.m1 === obj.m2);  //false

obj.m1();  //clicked
obj.m2();  //changed

例2:

var obj = new Object();
var events = {m1: 'clicked', m2: 'changed'};

for (var e in events) {
    (function() {
        //var aValue = e;
        obj[e] = function() {
            var aValue = e;
            console.log(events[aValue]);
        };
    }());
};

console.log(obj.m1 === obj.m2);  //false

obj.m1();  //changed
obj.m2();  //changed

以上两个例子中,除了var aValue = e;这一句位置不同:例1位于外层匿名函数中、例2位于内层匿名函数中,其他部分完全相同。但结果令我困惑,为什么?哪位帮忙分析下?谢谢!

—————————————————————————————————————————
PS.目前我的理解,一般来讲,同一个外层函数中的不同闭包(内层函数)的作用域链(本质上是一个指向变量对象的指针列表,参见《JavaScript高级程序设计(第3版)》P.179正文倒数第2段及P.180图7-2)引用的是外层函数的同一个活动对象;但是在例1中,因为立即执行函数两次独立执行的缘故,导致创建了两个不同的外层函数的活动对象,从而每个闭包的作用域链各自引用了其中的一个活动对象。如果有误,还望指教。

解决方案

闭包在函数声明的时候生成,它确定的是变量的查找路径而不是变量的值;变量的值在函数执行时才能确定

var obj = new Object();
var events = {m1: 'clicked', m2: 'changed'};

for (var e in events) {
    (function() {
        var aValue = e;//A
        obj[e] = function() {//B
            //var aValue = e;//A1
            console.log(events[aValue]);//C
        };
    }());//D
};

console.log(obj.m1 === obj.m2);  //E false

obj.m1();  //clicked
obj.m2();  //changed

D行定义了一个立即执行函数,函数在执行时引用了当前循环的e值并赋值给立即执行函数的局部变量aValue,B行定义了匿名函数,并且为obj对象添加了e表示的字符串值为属性名的一个属性,并且绑定到匿名函数。匿名函数使用到了D行定义的立即执行函数的局部变量aValue,立即执行函数完毕后,B行匿名函数有对立即执行函数的闭包,确定匿名函数中需要的变量aValue到立即函数中查找

下一次循环时,e变量指向的值发生变化,但先前生成的B匿名函数引用aValue变量值是不会跟着变化的,aValue变量值是确定的,在立即执行函数中。
每次循环B行声明的匿名函数对象都是不同的,立即执行函数对象也是不同的

因为有变量应用关系的存在,匿名立即执行函数不会被释放掉,其局部变量也会得到保留~~~

var obj = new Object();
var events = {m1: 'clicked', m2: 'changed'};

for (var e in events) {
    (function() {
        //var aValue = e;//A
        obj[e] = function() {//B
            var aValue = e;//A1
            console.log(events[aValue]);//C
        };
    }());//D
};

console.log(obj.m1 === obj.m2);  //false

obj.m1();  //changed
obj.m2();  //changed

和上面不同的地方将A行移动到A1行,看着似乎差不多,但是结果却不同
原因就在于B处声明的匿名函数,引用了最外层的变量e,构成对对外层函数的闭包;只是确立了变量引用了关系(确切的说确定了变量查找路径),但是具体的值在函数被执行前是无法预知的
等整个循环结束后, e的值为m2(这个也不一定,看events属性定义的顺序及属性值的获取手段),当obj属性绑定的函数被执行时,A1行aValue都为m2~~~~

这篇关于node.js - JavaScript闭包中令人困惑的一个奇怪问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆