javascript关闭局部变量超出范围?

时间:2013-12-25 00:56:53

标签: javascript scope closures

有人可以向我解释下面的代码中发生了什么吗?

function foo() {
    var x = [-1, 2, 1];
    setTimeout(function () {
        console.log(x);    
    }, 3000);
    return x;
}
var z = foo()
z[1] = 0;
console.log(z);

// result: [-1, 0, 1] and after 3 seconds [-1, 0, 1]. 

由于关闭,我期望第二次输出获得[-1,2,1]。但我不是。是因为x比foo()更久了,我能够使用z [1] = 0来改变它吗?请解释一下。

4 个答案:

答案 0 :(得分:2)

当一个函数返回一个数组或一个对象时,它实际上返回一个对它的引用,而不是原始值会发生的复制。例如,如果x是数字,字符串或布尔值,则您在函数外部所做的更改将不会在其中生效。

如果要返回数组的副本以获得预期的行为,可以使用slice方法。

function foo() {
    var x = [-1, 2, 1];
    setTimeout(function () {
        console.log(x);    
    }, 3000);
    return x.slice();
}

小提琴:http://jsfiddle.net/KbxMX/1/

答案 1 :(得分:1)

变量对象不同;对象是值,而变量名称(或“引用”)对象 1

使用[-1, 2, 1]创建的Array 对象可通过回调中的变量绑定x访问。但是,在回调运行之前,相同的数组对象(也已返回并分配给z在调用方中变异xz都命名相同的对象。

给定代码中只有一个 Array对象(由[-1, 2, 1]创建): objects (独立于变量)永远不会隐式复制,克隆或复制。 (如果需要重复,则必须相应地创建。)


1 说“..变量名称值”更合适。但是,在这种情况下,所讨论的特定值是数组(JavaScript中的真实对象)而不是数字或未定义的原始值。

我在引号中使用“引用”,因为可以在不引入包含来自其他语言和上下文的行李的术语的情况下解释行为。 ECMAScript规范不使用“引用”来讨论变量和对象之间的关联。相反,ES5使用内部函数PutValue(与Simple Assignment等结合使用)来描述“将值绑定到变量”的操作。

答案 2 :(得分:1)

当您return x引用传递到存储[-1, 2, 1]的内存中的位置时。这意味着xz 相同的对象 z不是克隆,并且可以看到对其中的任何更改在另一方面,因为他们只是为了同一件事的别名。

答案 3 :(得分:1)

  

是因为xfoo()更长,我可以使用z[1] = 0更改它吗?

x以两种方式超过foo的身体:

  1. 作为setTimeout回调中的闭包
  2. 作为返回值
  3. 正文中的

    x,返回的值和关闭的值仍然引用相同的数组。