我有些喜欢:
var i = 0;
var func = function(){
console.log(i);
};
func(); //0
i++;
func(); //1
我希望第二个控制台也输出' 0 ', 所以我改变了程序,如:
var i = 0;
var func = (function(_i){
return function(){
console.log(_i);
};
})(i);
func(); //0
i++;
func(); //0
我知道它是如何运作的,但是是否有任何名称或术语来描述这种机制?
答案 0 :(得分:4)
我一直在调用这种机制"breaking the closure"
,虽然我过去曾与那些坚持称这种技术的人"closure"
进行过争论。
我称之为"breaking"
关闭的原因是因为这就是你正在做的事情。
您看到的经典之处在于循环闭包的解决方案:
var hellos = [];
for (var i=0; i < 10; i++) {
hellos.push(
(function(j){
return 'hello ' + j
})(i)
);
}
问题是由外部变量和内部函数中对该变量的引用之间创建的闭包引起的(技术上,变量被称为“自由”变量而不是闭包,“闭包”在技术上指的是机制,捕获变量但是在js社区中我们最终调用了两个闭包的东西)。因此关闭是问题的原因。由于问题是由创建的闭包引起的,因此我开始将解决方案称为 "breaking the closure"
。
请注意,尽管有些人称这是一个闭包,你可能会谷歌搜索“js closure”来阅读更多关于这种技术的内容,但它具有讽刺性的而不是闭包。它是简单的函数如何传递参数(关于javascript如何实际将参数传递给函数,你可以在这里阅读:Why are objects' values captured inside function calls?)。 Javascript是一种相当严格的按值传递语言,就像C是一种严格的按值传递语言一样(C只能通过值传递)。
当您在js(对象,数组)中传递引用时,该函数将不会获取原始引用,而是获取引用的副本。由于它是一个引用,它显然指向与原始引用相同的对象,因此很容易错误地认为javascript通过引用传递。但是,如果您尝试将新对象分配给传入的引用,您会注意到原始引用不会更改。例如:
function foo (x) {
x = [2,3];
}
var y = [1,2];
foo(y);
console.log(y) // prints [1,2] so foo() did not change y
这个机制负责破坏外部变量(在您的示例中为i
)与内部变量(_i
)之间的关联例)。这个机制的名称只是函数调用(从技术上讲,它是函数调用的一个子集 - 它是如何将参数传递给函数调用的。)
所以回顾一下:
"breaking the closure"
"closure"
,即使它不是一个闭包(闭包是他们想要避免的)。旁注:我意识到原始示例是关于全局变量但是在javascript全局变量只是闭包的一个特例 - 当你定义一个函数时总是会创建闭包,只是当没有外部函数时范围只是全球范围。
答案 1 :(得分:1)
它被称为闭包。您可以在这里阅读更多相关信息:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
答案 2 :(得分:0)
当传入一个基本类型变量(如字符串或数字)时,该值将按值传入。这意味着在函数中对该变量的任何更改都与函数外部发生的任何内容完全分开。
如果未声明范围中的变量,它将搜索外部范围,直到找到它,或者搜索窗口范围。如果没有找到,它将变量全局。