3

我很难理解基于范围的 JavaScript 中的变量阴影。考虑这个小代码片段:

var k = {
    prop1: 'test',
    prop2: 'anotherTest'
}

for(var k = 0; k < 10; k++) {
    console.log(k);
}

//prints number
console.log(typeof k);

//prints 10
console.log(k);

//undefined
console.log(k.prop1);

这很好,因为由于立即函数作用域,循环计数器变量 k 会影响我们之前声明的 json 变量 k。因此,可以说 json 变量 k 变得不可访问。

问题:


  1. 在内存分配方面,既然没有办法访问原始的json var k,是否有资格进行垃圾回收?分配的内存会被释放吗?还是“引用孤儿”变量仍然存在?如果是,为什么以及持续多长时间?

  2. 有没有一种方法可以访问原始 json var k 而无需在 for 循环之前编写任何代码?

现在考虑另一个稍作修改的代码片段:

var k = {
    prop1: 'test',
    prop2: 'anotherTest'
}

var m = {
    prop1: k
}

for(var k = 0; k < 11; k++) {
    console.log(k);
}

//prints number
console.log(typeof k);

//prints 10
console.log(k);

//undefined
console.log(k.prop1);

//reference altered? No, this reference points to the original json k
//firebug dumps object to console
console.log(m.prop1);

问题:


  1. 这一次,我们事先在另一个 json 对象中保存了对原始 k 的引用。当然,内存不会被释放。但是,评估 m.prop1 不会解析为更新后的整数 k,其值为 10?为什么这个分辨率不会导致值为 10 的循环计数器?
4

1 回答 1

3

1#在内存分配方面,既然没有办法访问原始的json var k,是否有资格进行垃圾回收?分配的内存会被释放吗?还是“引用孤儿”变量仍然存在?如果是,为什么以及持续多长时间?

只有一个变量叫做kvar 不“声明一个变量” 1在其他语言的意义上。这里没有阴影。相反,它是一个提升到函数顶部的注释。

先前已知的对象k不再是强可达的,因此可以回收。(具体何时依赖于实现,但它是合格的。)

2# 有没有办法访问原始的 json var k 而无需在 for 循环之前编写任何代码?

只有一个变量叫做kvar 不“声明一个变量” 1在其他语言的意义上。这里没有阴影。相反,它是一个提升到函数顶部的注释。

循环中的赋值会覆盖相同 k的变量。

3#这一次,我们在另一个json对象中保存了对原始k的引用。当然,内存不会被释放。但是,评估 m.prop1 不会解析为更新后的整数 k,其值为 10?为什么这个分辨率不会导致值为 10 的循环计数器?

变量不是对象。表达式,包括变量名,在 JavaScript中被急切地求值。评估时由变量命名的对象现在由 命名。因此,为变量分配新值对先前评估的内容没有影响。km = { prop1: k }m.prop1 kk

JavaScript 中对变量的唯一引用出现在赋值的左侧或像typeofor之类的运算符del。否则,变量永远不会在表达式产生中被引用。不要将引用与Call-By-Object-Sharing或“对象变异”语义混淆:更改对象的属性会使对象发生变异。(如所见,某些类型number不可变的,不允许自定义属性“粘贴”。)


以上假设代码出现在函数中。在任何函数之外的规则var略有不同——在这种情况下,它声明局部变量,而k只是(仍然)引用全局window.k属性。

1正确的术语“声明”;但是,我发现将其视为注释,因为它是一个函数范围的属性,x并且在陈述的意义上不是“评估”的,所以更清楚。例如,这两个函数是等价的:

function () { var x = 1; return x }
function () { x = 1; return x; var x }

也可以看看:

于 2012-06-20T05:46:56.783 回答