技术解析

如何解释这段 JavaScript 代码的输出结果?
0
2021-08-09 21:03:49
idczone

演示地址: https://jsbin.com/sepapegiga/edit?html,js,console,output


这里是个 array of function
这里的 rule 只是一个入参的代号,并不是一个变量

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

又不是全局变量,为什么会被覆盖

因为每次函数执行都是不同的作用域(上下文?),所以并不会覆盖

内部函数可以访问外层函数的作用域里的变量,我是这么理解的;
定义的时候匿名函数的 rule 就是访问的外部函数里的变量;而且外部函数每次执行的时候都会重新声明一次 rule,所以不会互相覆盖;可以在匿名函数里打断点来查看调用栈;
如果使用 this.rule 来保存就会不一样了

似乎形成闭包了

基础不扎实

我的理解是闭包了,保存了当时的上下文 rule 。

2 楼正解。

你每次执行 add 方法都声明了一个新的 rule,所以他们各自引用的是不同的对象

没有立即执行函数和 return 操作很多人就不认识闭包了
按照闭包的解释,每次执行.add 操作的时候,在其内部会形成**一个独立的词法环境**,在这个词法环境中新创建的匿名函数(被 push 那个)会记住对环境中变量的引用,因为你在函数里内部执行了 console.log(rule),用到了当时环境中的 rule,所以这个 rule 变量会跟函数绑在一起,形成闭包
你第二次执行 add 操作的时候,形成的是新的运行时上下文,push 进去的函数也是新的,该函数捆绑的变量也是新的,也就是一个新的闭包,所以不会覆盖上一次用到的变量
你可以在 Chrome 的调试工具里用 console.dir()把最后一步 forEach 中的 fn 打印出来,可以看到闭包里面具体引用了哪些内容

闭包,建议重新理解。

这不就是闭包吗

形成闭包了,匿名函数访问的变量 Rule 不会释放。
每次执行 add 方法,都会存储一个新的 Rule 变量以及值,通常在方法结束之后,这个变量会被释放,
但是有闭包的情况,不会释放。

基本知识,没学好。

我后端,光看个标题就知道是闭包问题了(狗头

我还在想有什么可解释的,竟然是在说作用域?
请回炉从 SICP 重造

就是不会被覆盖,因为两次执行了 add 方法,var rule 发生了两次

闭包

function 其实有两种调用模式,一种是函数,另一种是对象方法;不同调用模式表现出不同的特性,最直接的区别就是 function 运行的上下文。
add 是声明在 RuleSystem 类(或者说是 RuleSystem 构造函数的原型)上的,当 new 出一个 ruleSystem 对象的时候,调用 ruleSystem.add 就是调用对象方法的模式,它的上下文是 ruleSystem 对象本身,所能直接操作 ruleSystem 的 rules 数组。
在 add 方法内部向 rules push 的 item 是个 funciton,这个 funciton 不在原型链上,调用的时候是普通的函数调用模式,所以它的上下文是它所在的作用域(跟写 C 语言差不多),用到 rule 的时候就会自然向外层一层一层搜索 rule 这个关键字,于是找到了 var rule='Rule '+rule 。
当你每次调用 add 方法的时候,都会产生一个新的局部作用域,这个作用域里有个 rule 变量,你一共调用了 2 次 add 方法,所以创建了 2 个局部作用域,这两个作用域里的 rule 值不一样,一个是"Rule A",另一个是"Rule B";两次 push 也都是在上述两个作用域里分别执行的,push 到 rules 的 function 里的 rule 也都是引用各自作用域里离它最近的那个 rule 。
这时候代码等价于:
var rules=[];
var add=function(rule){
var rule='Rule '+rule
rules.push(function(){
console.log(rule)
})
}
两者区别仅仅是 rules 放在对象里还是直接放在上层作用域里,其余都是完全等价的。
如果你希望 rules 数组里的所有函数中的 console.log(rule)都输出最后产生的 rule 值,你应该把 add 方法内部的 rule 变量换成一个公共变量,就是每次调用 add 方法不会重新创建的那种,比如直接放在上层作用域里,或者用 this.rule 。

我倒不觉得反直觉 不就应该这样么

词法作用域+闭包

闭包 下一位

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服