Javascript 与';与';声明和电话
结果未定义,30,20Javascript 与';与';声明和电话,javascript,with-statement,ecma262,Javascript,With Statement,Ecma262,结果未定义,30,20 如果您能以逐步调试的方式解释这一工作原理,我们将不胜感激。通常建议您。真让人困惑 也就是说,如果我们只对代码进行注释,这可能是最简单的。我将您的匿名对象称为{},而不是this,以避免歧义。这里的顺序切换仅仅是为了按照从上到下的执行顺序读取代码 var a = ({ x: 10, foo: function () { function bar() { console.log(x); conso
如果您能以逐步调试的方式解释这一工作原理,我们将不胜感激。通常建议您。真让人困惑 也就是说,如果我们只对代码进行注释,这可能是最简单的。我将您的匿名对象称为
{}
,而不是this
,以避免歧义。这里的顺序切换仅仅是为了按照从上到下的执行顺序读取代码
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();
清澈如泥?(如果可以避免的话,不要将
与一起使用!)好的,让我们先简化一下代码。我已经重构出foo
是一种方法,它不需要演示意外行为
var a = ({
x: 10,
foo: function () {
// entering `with(this)`: all variables are searched against `{}`
// before the engine attempts to create a new variable:
with (this) {
// `var x` creates a local `x`. But, during assignment,
// `x` matches `{}.x`, so `{}.x` is set. **local `x`**
// remains `undefined`.
var x = 20;
// `y` isn't found in `{}`, so it's a local variable
var y = 30;
// execute `bar()`
bar.call(this);
}
// we're now in scope of `{}.foo()`, but not `with(this)`.
function bar() {
// local variable `x` was declared, but never defined.
console.log(x);
// local variable `y` exists in the scope of `{}.foo()`
console.log(y);
// we're still in the "macro" scope of `{}`. So, `this` refers
// to `{}`, which was changed to 20.
console.log(this.x);
}
}
}).foo();
那么,当我们调用foo
时会发生什么呢
设置并填充声明的函数和变量。这就是所谓的“吊装”。在foo
中,有函数bar
和变量x
和y
(函数foo
本身及其参数a
,仅在我的重构版本中)。这是bar
可以访问的范围
执行该命令。它将当前词汇环境与基于a
对象的词汇环境进行交换,该对象的任何属性现在都可以像变量一样访问
值20
分配给x
。这是什么x
?解析该标识符时,将选中a
对象,-oh-它具有与该名称的绑定!因此我们将值放入该绑定中,这将把20
放在对象的.x
属性上
值30
分配给y
。这是什么?再次检查当前词汇环境,但在a
对象上找不到y
属性。因此,我们继续讨论父环境,它包含上面创建的x
,y
,bar
变量。实际上,这里我们找到了一个y
变量,因此我们将值30
放在该插槽中
调用条
函数。再次,设置一个新的执行上下文(如上所述),其中步骤1中的一个作为其父范围(由bar
在foo
中的词法位置确定,此时bar
函数被实例化-词法闭包)。现在,我们记录这三份意向书:
x
解析为foo
范围内的变量x
,该变量的值仍为未定义
y
解析为foo
范围内的变量y
,该变量保存我们刚刚分配的值30
a.x
解析为a
对象的x
属性,该属性保存我们刚刚分配的值20
实际上,有一个x
变量(虽然不是bar
的局部变量)。@Bergi它不是局部变量。这就是重点。由于with
,它是对象的属性。它是foo
的局部变量。检查我的答案以了解解释:-)你可以让条使用严格模式,它不会抛出任何错误。@Bergi我可能在术语上弄错了;但我认为这是一个标识符;不是一个变量。它实际上是未定义的@svidgen:它也适用于变量声明。在任何var xyz=123
类型的操作中,var xyz
部分被提升,但赋值保持不变。坦率地说,我不能理解x==undefined的意义,我的意思是我知道当with
语句终止时,它会删除它作为扩展范围对象操作的对象的所有更改,但是在我们的例子中,我们不终止它,我们继续从我们未命名的对象调用一个本地方法,这有点让人困惑…Bergi:也许值得重写代码,将提升机放在它们的最终目的地。“当with语句终止时,它会删除它所操作的对象的所有更改”-不,你怎么会这样认为?顺便说一句,将bar()
调用移出带有语句的也没有什么区别。不完全是这样。它将词法环境更改回原始环境,是的,但不会恢复对这两个环境所做的修改。使用
的所“插入”的环境是原始环境的子环境,并代理在对象上找到的属性。看这可能会有点帮助:
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});