var a = ({
x: 10,
foo: function () {
function bar() {
console.log(x);
console.log(y);
console.log(this.x);
}
with (this) {
var x = 20;
var y = 30;
bar.call(this);
}
}
}).foo();
结果为undefined,30,20。
非常感谢您逐步了解调试方式,以了解其工作原理。
好了,让我们先简化一下代码。我已经将其重构foo
为一种方法,不必证明这种意外行为。
function foo(a) {
// var x, y, bar - hoisting
function bar() {
console.log(x);
console.log(y);
console.log(a.x);
}
with (a) {
var x = 20;
var y = 30;
bar();
}
}
foo({x:10});
那么,当我们打电话时会发生什么foo
呢?
foo
,有函数bar
和变量x
和y
(以及函数foo
本身及其参数a
,仅在我的重构版本中)。这是bar
可以访问的范围。a
对象的环境交换当前的词法环境-可以像访问变量一样访问其任何属性。20
分配给x
。这是x
什么 解析该标识符时,将a
检查对象,并且-哦-它具有与该名称的绑定!因此,我们将值放在该绑定中,这会将对象20
的.x
属性放在。30
分配给y
。这是y
什么 再次检查当前的词法环境,但我们y
在a
对象上找不到属性。所以,我们去到父的环境,这是一个用x
,y
,bar
上面创建的变量。确实,在这里我们找到了一个y
变量,因此我们将值30
放在该插槽中。bar
函数被调用。再次,设置新的执行上下文(如上),将步骤1中的上下文作为其父范围(由实例化函数时bar
in的词法位置确定-词法闭包)。现在,我们记录这三个感兴趣的表达式: foo
bar
x
解析为x
范围内的变量,该变量foo
仍具有值undefined
。y
解析为y
范围内的变量,该变量foo
保存30
我们刚刚分配的值。a.x
解析为对象的x
属性,该属性a
保存20
我们刚刚分配的值。本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句