【问题标题】:Scope based variable shadowing in JavaScriptJavaScript 中基于作用域的变量阴影
【发布时间】:2012-06-20 05:25:39
【问题描述】:

我很难理解 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. 这一次,我们事先保存了对原始 k 的引用,在 另一个 json 对象。当然,记忆不会 取消分配。但是,不会评估 m.prop1 解析为更新 整数 k,值为 10?为什么这个决议没有导致 值为 10 的循环计数器?

【问题讨论】:

  • 我不确定您的前两个问题...不确定垃圾收集在 JS 中的工作原理并假设它是特定于环境的...但是对于最后一个问题,m 没有理由指向k...当您在m的实例化中分配prop1:k时,您将k的引用指针传递给对象m...然后当您用var k=0覆盖时,您说的是当前变量名k 应该与一个全新的对象相关联...对它的原始引用只字不提...对不起,如果我的回答令人困惑,我认为我的措辞不是很好...
  • 只有一个变量称为k。变量命名对象。变量不是对象。

标签: javascript function scope


【解决方案1】:

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

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

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

2#有没有办法在for循环之前不用写任何代码就可以访问原始的json var k?

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

循环中的赋值覆盖了同样的k变量。

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

变量不是对象。表达式,包括变量名,在 JavaScript 中急切地评估。当m = { prop1: k }评估 时,由变量k 命名的对象现在由m.prop1 命名。因此,将新值分配给 变量 kk 以前 评估的结果没有影响。

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


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

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

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

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    相关资源
    最近更新 更多