javascript - 关于一个js闭包里的作用域链的问题
迷茫
迷茫 2017-04-10 17:57:36
[JavaScript讨论组]

直接上代码代码简单

function Foo(){
     var i=0;
     return function(){
         document.write(i++);
     }
}
var f1=Foo(),
f2=Foo();
f1(); 
f1();
f2();


问题,被引入到外部作用域是如果保存的,答案是010,f1和f2如何实现的隔离,如果有图的话就更好了;我觉得大部分网上关于闭包都讲得太抽象,不够具体和直接
i这个变量到底保存在哪个作用域,f2、f1不指向一个函数作用域么

迷茫
迷茫

业精于勤,荒于嬉;行成于思,毁于随。

全部回复(12)
天蓬老师

你可以把 f1 = Foo()当作一个变量赋值;

所以 f2 和 f1 中的i 互不影响,因为都在各自新的作用域内。

PHPz

留意Foo的定义,里面用var定义了一个闭包内的变量i,每执行一次Foo就初始化一个新的i,这就是f1和f2的里的i分别独立的原因。

但对于f1来说,f1每次执行都是指向同一个i,就是f1 =Foo()这一句初始化的i,每次执行都给它加1。

黄舟

这么跟你说吧:在为f1f2赋值的时候调用Foo()会将i重新设为0。而运行f1f2的时候只是在运行闭包,跟var i = 0;没有关系了。

天蓬老师

F1和F2中的i都是放在单独的作用域中,互不影响的人

黄舟

我自己的理解,仅作参考。
函数定义有三种方式:其中一种就是字面量方式。
var f1 = function(){}
你的Foo()返回的返回值是一个匿名函数,如果从函数定义的角度来说
var f1 = Foo() 等价于 var f1 = function(){document.write(i++)}
var f2 = Foo() 等价于 var f2 = function(){document.write(i++)}

然后根据闭包,作用域链的相关知识。(楼上的朋友已经有回答)
f1(),第一次执行后0。
f1(),第二次执行后1。

f2(),第一次执行后0。

这只是我自己的拙见,仅供参考。

怪我咯

两次执行Foo,虽然都是返回 funtion(){} 但是两次返回的其实不是同一个function 你只要执行一下 f1==f2 就知道了,既然返回的是两个不同的function 那么 他们对应的scope肯定也是不同的。

高洛峰

f1和f2引用的是两个执行环境

PHP中文网

你要的图来了!

1. 刚定义完函数Foo时:

2. 所有代码执行完时:

3. 说明一下:

问题的关键时:

(1) 函数在执行期间会产生一个执行上下文(EC),作为函数的运行时表示,函数返回时此上下文销毁。所以很函数Foo被调用了两次必然产生两个不同的执行上下文。

(2) 执行上下文中有个叫做词法环境(LE)的东西,用来存放函数执行时产生的局部变量、this等东西。函数Foo里面的局部变量i就放在词法环境LE里面。

(3) 函数返回后,执行上下文销毁了,但是词法环境还是可以存在的,所以你要问i存放在哪里?不错,就在词法环境里面。

(4) 函数里面定义的内部函数总是有一个内部指针(即图中的[[scope]])指向外部词法环境。所以f1和f2可以引用它们的外部词法环境中的各自的i变量,并对它们进行操作。

如果还有什么不明白的,可以留言。

注:为了方便理解,图中某些地方进行了简化,但是本质没有变化。

迷茫

Foo 每次执行时会产生一个新的scope, f1和f2分别绑定到两个这样的scope, 里面各有一个同名变量i

天蓬老师

楼主,这个貌似不太好用图来说明,这里每次调用Foo()函数时,都会执行一次var i=0; 而 f1 和 f2 是分两次调用的,所以会生成两个完全独立的 i 变量,尽管名字相同,但是却是生存在两个不同的作用域中的变量,执行 f1 函数不会影响 f2 函数中的 i 的值,反之执行 f2 同样也不会影响 f1中 i 的值,f1 和 f2 只和各自的 i 变量保持着联系。不知这样会不会好理解一点

ps: 这是另一个类似问题中用户 bachelor 的回复,我觉得解释的还比较明朗:

楼上的各位都在关注闭包,其实题主更应该关注的是这个变量i,因为你每执行这个函数,变量i就重新初始化。
正应为重新执行函数以后,才得到的楼主的答案。

继续回到题主的问题上,如果想让i不被重新执行函数的时候初始化,该怎么办?很简单。

  1. 将变量i变成相对于函数外全局变量,也就是如下这样:

    var i = 0;
    function Foo() {

       return function() {  
          console.log(i++);  
       }  

    }

    var f1 = Foo(),

       f2 = Foo();  

    f1(); // 0
    f1(); // 1
    f2(); // 2

2 不用var声明,不过这样是不推荐的,容易造成变量混乱。

function Foo() {  
    i = 0; 
    return function() {  
       console.log(i++);  
    }  
}  

var f1 = Foo(),  
    f2 = Foo();  
f1(); // 0
f1(); // 1
f2(); // 2
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号