第二章.重点1

第二章:重点

词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。编译的词法分析阶段 基本能够知道全部标识符在哪里以及是如何声明的,从而能够预测在执行过程中如何对它 们进行查找。

function foo(obj) { with (obj) {
a = 2; }
}
var o1 = { a: 3
};
var o2 = { b: 3
};
     foo( o1 );
     console.log( o1.a ); // 2
foo( o2 );
console.log( o2.a ); // undefined

console.log( a ); // 2——不好,a 被泄漏到全局作用域上了!

这个例子中创建了 o1 和 o2 两个对象。其中一个具有 a 属性,另外一个没有。foo(..) 函 数接受一个obj参数,该参数是一个对象引用,并对这个对象引用执行了with(obj) {..}。

在 with 块内部,我们写的代码看起来只是对变量 a 进行简单的词法引用,实际上就是一个 LHS 引用(查看第 1 章),并将 2 赋值给它。
当我们将 o1 传递进去,a=2 赋值操作找到了 o1.a 并将 2 赋值给它,这在后面的 console. log(o1.a) 中可以体现。而当 o2 传递进去,o2 并没有 a 属性,因此不会创建这个属性, o2.a 保持 undefined。

eval(..) 函数如果接受了含有一个或多个声明的代码,就会修改其所处的词法作用域,而 with 声明实际上是根据你传递给它的对象凭空创建了一个全新的词法作用域。

可以这样理解,当我们传递 o1 给 with 时,with 所声明的作用域是 o1,而这个作用域中含 有一个同 o1.a 属性相符的标识符。但当我们将 o2 作为作用域时,其中并没有 a 标识符, 因此进行了正常的 LHS 标识符查找(查看第 1 章)。
o2 的作用域、foo(..) 的作用域和全局作用域中都没有找到标识符 a,因此当 a=2 执行 时,自动创建了一个全局变量(因为是非严格模式)。

with 这种将对象及其属性放进一个作用域并同时分配标识符的行为很让人费解。但为了说 明我们所看到的现象,这是我能给出的最直白的解释了。

你可能感兴趣的:(第二章.重点1)