我很难理解基于范围的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可以说是不可访问的。
问题:
<小时/>
现在考虑另一个稍微修改过的代码片段:
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);
问题:
<小时/>
答案 0 :(得分:3)
1#就内存分配而言,既然没有办法访问原来的json var k,它是否有资格进行垃圾回收?分配的内存是否会被释放?或者'参考孤儿'变量仍然存在?如果是,为什么以及持续多久?
只有一个变量名为k
。 var
不会在其他语言的意义上“声明变量” 1 。这里没有阴影。相反,它是一个注释解除到函数的顶部。
k
之前已知的对象不再强烈可访问,因此可以回收。 (确切当依赖于实现时,但它符合条件。)
2#有没有办法在for循环之前写入任何代码来访问原始json var k?
只有一个变量名为k
。 var
不会在其他语言的意义上“声明变量” 1 。这里没有阴影。相反,它是一个注释解除到函数的顶部。
循环中的赋值会覆盖相同的 k
变量。
3#这次,我们在另一个json对象中持有对原始k的引用。当然,内存不会被解除分配。但是,不会评估m.prop1解析为更新的整数k,值为10?为什么这个分辨率不能导致循环计数器的值为10?
变量不是对象。表达式(包括变量名称)在JavaScript中进行急切评估。 k
评估时,变量m = { prop1: k }
名为的对象现在由m.prop1
命名。因此,为变量 k
分配新值对k
之前评估的内容没有任何影响。
JavaScript中对变量的唯一引用显示在作业的左侧或typeof
或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 }
另见: