我对这个关闭事情感到困惑。我下面有两个单独的代码看起来相似,但它们的输出是不同的。
function setup(x) {
var array = [];
for(var i=0;i<arguments.length;i++){
array[i]= arguments[i];
}
return array;
}
console.log(setup('a','b')); // will output ["a","b"]
--------------
function f() {
var i, array = [];
for(i = 0; i < 3; i++) {
array[i] = function(){
return i;
}
}
return array;
}
var a = f();
console.log(a()); //output: [function(),function(),function()]
console.log(a[0]()); //output: 3 //same output in a[1]() and a[2]() calls as well
现在我的问题是,输出结果如何不同?上面的两个代码都返回一个数组。在第一个代码中,它正确打印数组中的所有元素,而在第二个代码中,为什么不打印[1,2,3] ???
答案 0 :(得分:4)
在第二个示例中,您在循环中创建3
函数,但所有函数都在同一变量范围内创建,因此它们都引用并返回相同i
变量的值
因此,从函数返回的i
的值表示调用函数时的值。因为您在循环之后调用它们,i
的值为3
,所以这是返回的值。
这就是封闭的含义。这些函数“关闭”创建它们的变量范围中存在的变量。它们不会关闭变量的值,而是关闭变量本身,因此它们总是得到变量的当前状态。
对于引用i
的不同值的每个函数,需要在具有自己唯一i
的单独变量范围中创建每个函数。
因为在JavaScript中创建新变量作用域的唯一方法是调用函数,所以需要在新函数调用中创建每个函数。
function makeFunction(j) {
return function(){
return j;
};
}
function f() {
var i, array = [];
for(i = 0; i < 3; i++) {
array[i] = makeFunction(i);
}
return array;
}
所以我在这里创建了一个名为makeFunction
的新函数。它接收一个参数,并返回一个引用并返回该参数的新函数。
因为makeFunction
的每次调用都会创建一个新的唯一变量作用域,所返回的每个函数都将引用其自己唯一的j
变量,因此将返回存在的j
值调用时调用makeFunction
(除非您的函数修改j
,如果您愿意,可以执行此操作)。
请注意,为清晰起见,我使用了变量名j
。您也可以使用i
或其他名称。
答案 1 :(得分:0)
在JavaScript中,您有函数语句和函数表达式。第一个声明命名函数,后者计算命名或匿名函数。你正在使用函数表达式。
我认为您想要做的是调用表达式。您所要做的就是立即调用返回i
的函数。
function f() {
var i, array = [];
for (i = 0; i < 3; i++) {
// The extra parentheses around the function are unnecessary here.
// But this is more idiomatic, as it shares syntax with how function
// expressions are introduced in statements.
// I.e. you could just copy-paste it anywhere.
array[i] = (function () {
return i;
})(); // don't rely on automatic semicolon insertion
}
return array;
}
另请注意,在您的问题示例中,所有闭包都返回3
,因为它们都捕获相同的变量i
。
编辑:为了使前一段更清晰,如果你真的想拥有3个不同的闭包,你必须为每个闭包创建一个新的范围。与其他语言不同,Javascript不会仅通过打开块来创建范围。它只在函数中创建范围。这有两种方法:
function f() {
var i, array = [];
for (i = 0; i < 3; i++) {
// With a parameter in an inner function
array[i] = (function (n) {
return function () {
// A new n is captured every time
return n;
};
})(i);
}
return array;
}
function f() {
var i, array = [];
for (i = 0; i < 3; i++) {
array[i] = (function () {
// With a variable in an inner function
var n = i;
return function () {
// A new n is captured every time
return n;
};
})();
}
return array;
}
然而,下一个例子是错误,因为即使在n
块中声明了for
,它也就好像它已在顶部声明一样该函数只在for
块中初始化。请记住,这是JavaScript,而不是Java,不是C,不是C#,不是&lt;无论是括号中的语言&gt;:
function f() {
var i, array = [];
for (i = 0; i < 3; i++) {
var n = i;
array[i] = function () {
return n;
};
}
return array;
}
等效代码:
function f() {
var i, array = [];
var n;
for (i = 0; i < 3; i++) {
n = i;
array[i] = function () {
return n;
};
}
return array;
}