一些复杂的行为与'带有'语句和调用

Some complex behaviour with 'with' statement and call

本文关键字:带有 语句 调用 复杂      更新时间:2023-09-26
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();

导致未定义,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时会发生什么呢?

  1. 执行上下文是用声明的函数和变量设置和填充的。这就是俗称的"吊装"。在foo中,有函数bar、变量xy(以及函数foo本身及其参数a,仅在我的重构版本中(。这是bar可以访问的范围
  2. 执行with语句。它将当前的词法环境与基于a对象的词法环境进行交换,其中的任何属性现在都可以像变量一样访问
  3. 值CCD_ 11被分配给CCD_。这个x是什么?解析该标识符时,会检查a对象,并且-哦-它有一个具有该名称的绑定!因此,我们将值放入绑定中,这将把20放在对象的.x属性上
  4. 值CCD_ 17被分配给CCD_。这个y是什么?再次检查当前的词法环境,但在a对象上找不到y属性。因此,我们继续到父环境,它包含上面创建的xybar变量。实际上,在这里我们找到了一个y变量,所以我们将值30放在该槽中
  5. 调用bar函数。同样,建立了一个新的执行上下文(如上所述(,将来自步骤1的上下文作为其父范围(这是由barfoo中的词法位置决定的,当bar函数被实例化时-词法闭包(。现在我们记录这三种兴趣表达:
    • x解析为foo范围内的变量x,该变量仍具有值undefined
    • y解析为foo范围内的变量y,该变量包含我们刚刚分配的值30
    • a.x解析为a对象的x属性,该属性包含我们刚刚分配的值20

通常建议您避免使用with。太令人困惑了!

也就是说,如果我们只是注释您的代码,这可能是最简单的。为了避免歧义,我将您的匿名对象称为{},而不是this。这里排序中的切换只是为了按照从上到下的执行顺序读取代码。

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();

清澈如泥?(如果可以避免的话,不要使用with!(