在 with{ } 语句中使用 'var' 声明变量

Declare a variable using 'var' in a with{ } statement

我正在研究关于 github 的 You-dont-know-js 书,目前范围关闭,第 2 章:https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch2.md

遇到了一个不太清楚的问题:在with{}语句中使用'var'声明变量。 对此的解释如下:

Note: Even though a with block treats an object like a lexical scope, a normal var declaration inside that with block will not be scoped to that with block, but instead the containing function scope.

根据这个解释,我对本章提供的代码做了一点改动:

function foo(obj) {
 with (obj) {
  var a = 2;  //Here I added "var" declaration 
 }
  console.log('foo, '+ a)  //Here I added console function to see if a is in foo scope
}

var o1 = {
 a: 3
};

var o2 = {
 b: 3
};

foo( o1 );   // foo, undefined
console.log( o1.a );     //2

foo( o2 );   // foo, 2
console.log( o2.a );    //undefined

对于 foo(o2),我的理解是因为 o2 没有 属性 命名为 'a',with 块中的 var 声明只是在 foo 函数范围内创建了一个变量 a,并且结果是有道理的。 但是对于foo(o1)来说,var声明只是把o1.a改成值2,但是为什么console.log('foo, '+a)显示'foo, undefined'呢?据我了解,结果应该是 'foo, 2' 或引用错误:a 未定义。

谁能解释一下这个问题?谢谢。

编译器的作用:

function foo(obj) {
    var a;                   // hoisted
    with (obj) {
        a = 2;               // take a from object if exists, otherwise take variable
    }
    console.log('foo, '+ a);
}

第一种情况在函数范围内创建一个a变量,然后var语句是removed/hoisted,只剩下赋值部分。

虽然 obj 包含 属性 a,但该值是通过 with 语句分配给对象的 属性。

本地 a 没有收到任何值。

在第二次调用中,没有 a 的 属性,因此变量 a 得到一个值。