如果“与”是Javascript 中的语句创建了一个新的作用域,为什么这个闭包不包含新的“x”?每次都在新的范围内?

发布于 2024-08-31 01:01:43 字数 628 浏览 4 评论 0原文

如果 Javascript 中的 with 语句创建了一个新范围,那么单击链接是否不应该显示处于不同范围的不同 x ?事实并非如此。

<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>


<script type="text/javascript">

    for (i = 1; i <= 5; i++) {

        with({foo:"bar"}) {
            var x = i;
            document.getElementById('link' + i).onclick = function() { alert(x); return false; }
        }

    }

</script>

If the with statement in Javascript creates a new scope, shouldn't clicking on the links show a different x which are in different scopes? It doesn't.

<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>


<script type="text/javascript">

    for (i = 1; i <= 5; i++) {

        with({foo:"bar"}) {
            var x = i;
            document.getElementById('link' + i).onclick = function() { alert(x); return false; }
        }

    }

</script>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

像极了他 2024-09-07 01:01:43

with 语句不会创建一个全新的词法作用域,它只是在作用域链前面引入一个对象,例如,如果您捕获 i 变量,它会工作

for (var i = 1; i <= 5; i++) {
  with({x:i}) {
    document.getElementById('link' + i).onclick = function() {
      alert(x);
      return false;
    };
  }
}

让我尝试用另一个例子更好地解释它:

var x = 10, y = 10;   // Step 1

with ({x: 20}) {      // Step 2

  var x = 30, y = 30; // Step 3

  alert(x); // 30
  alert(y); // 30
}

alert(x); // 10
alert(y); // 30

在步骤 1 中,x< /code> 和 y 变量已声明,它们是作用域链中第一个对象(全局对象)的一部分。

步骤 2 中,通过 with 语句将一个新对象 ({x:20}) 引入到作用域链中,现在作用域链看起来像这样:

   ________              ________
  | x = 10 | <--------- | x = 20 |
  | y = 10 |             ¯¯¯¯¯¯¯¯¯
   ¯¯¯¯¯¯¯¯ 

在 第 3 步,执行另一个 var 语句,但它没有任何效果,因为正如我之前所说,只有函数才能创建完整的词法作用域。

var 语句没有效果,但赋值有效果,因此当 x 变量被解析时,会到达作用域链上的第一个对象,即我们使用

y 标识符也被解析,但在链中的第一个对象上找不到它,因此继续查找,并在最后一个对象上找到它,赋值后的作用域链如下所示:

   ________              ________
  | x = 10 | <--------- | x = 30 |
  | y = 30 |             ¯¯¯¯¯¯¯¯¯
   ¯¯¯¯¯¯¯¯ 

with语句结束时,作用域链最终恢复:

   ________ 
  | x = 10 |
  | y = 30 |
   ¯¯¯¯¯¯¯¯ 

编辑:
我稍微展开一下,讲讲函数。

函数被创建时,其当前父作用域被绑定,例如

var fn;
// augment scope chain
with ({foo: "bar"}) {
  fn = function () { // create function
    return foo;
  };
}​​
// restored scope chain
fn(); // "bar", foo is still accessible inside fn

:当函数执行时,新的词法作用域被创建并添加到作用域链中。

基本上,函数参数的所有标识符(名称)、用 var 声明的变量以及用 function 语句声明的函数,都被绑定为在幕后创建的新对象的属性,只是在函数本身执行之前(当控件进入这个新的执行上下文时)。

该对象无法通过代码访问,称为变量对象,例如:

var x = 10, y = 10;   // Step 1

(function () {        // Step 2
  var x, y; 

  x = 30;             // Step 4
  y = 30; 

  alert(x); // 30
  alert(y); // 30
})();                 // Step 3

alert(x); // 10       // Step 5
alert(y); // 10

在步骤 1 中,再次与我的第一个示例一样,xy 变量被声明,它们是作用域链中第一个对象(全局对象)的一部分。

在第2步中,创建了一个新的函数对象,父作用域此时存储在该函数的[[Scope]]中,现在包含xy

在步骤 3 中,调用该函数,启动变量实例化 process,它在作用域链中创建一个新对象,包含在这个新函数中声明的本地作用域的 x 和 y 变量,此时的作用域链如下所示:

  parent scope           Variable Object
   ________              _______________
  | x = 10 | <--------- | x = undefined |
  | y = 10 |            | y = undefined | 
   ¯¯¯¯¯¯¯¯              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 

然后在第4步中,完成了xy的赋值,但由于新的词法作用域已经创建,因此它不会影响外部值。

  parent scope           Variable Object
   ________              ________
  | x = 10 | <--------- | x = 30 |
  | y = 10 |            | y = 30 | 
   ¯¯¯¯¯¯¯¯              ¯¯¯¯¯¯¯¯ 

最后,在第 5 步中,函数结束,作用域链恢复到原始状态。

   ________ 
  | x = 10 |
  | y = 10 |
   ¯¯¯¯¯¯¯¯ 

推荐讲座:

The with statement doesn't creates a full new lexical scope, it just introduces an object in front of the scope chain, for example, if you capture the i variable, it will work:

for (var i = 1; i <= 5; i++) {
  with({x:i}) {
    document.getElementById('link' + i).onclick = function() {
      alert(x);
      return false;
    };
  }
}

Let me try to explain it better with another example:

var x = 10, y = 10;   // Step 1

with ({x: 20}) {      // Step 2

  var x = 30, y = 30; // Step 3

  alert(x); // 30
  alert(y); // 30
}

alert(x); // 10
alert(y); // 30

In the Step 1, the x and y variables are declared and they are part of the first object in the scope chain, the global object.

In the Step 2, a new object ({x:20}) is introduced into the scope chain by the with statement, now the scope chain looks something like this:

   ________              ________
  | x = 10 | <--------- | x = 20 |
  | y = 10 |             ¯¯¯¯¯¯¯¯¯
   ¯¯¯¯¯¯¯¯ 

In the Step 3, another var statement is executed, but it has no effect because as I said before, only functions create a full lexical scope.

The var statement has no effect, but the assignment has, so when the x variable is resolved, is reached on the first object on the scope chain, the one we introduced using with.

The y identifier is resolved also, but it is not found on the first object in the chain, so the lookup continues up, and finds it on the last object, the scope chain after the assignments looks like this:

   ________              ________
  | x = 10 | <--------- | x = 30 |
  | y = 30 |             ¯¯¯¯¯¯¯¯¯
   ¯¯¯¯¯¯¯¯ 

When the with statement ends, the scope chain is finally restored:

   ________ 
  | x = 10 |
  | y = 30 |
   ¯¯¯¯¯¯¯¯ 

Edit:
Let me expand a little bit and talk about functions.

When a function is created its current parent scope is bound, for example:

var fn;
// augment scope chain
with ({foo: "bar"}) {
  fn = function () { // create function
    return foo;
  };
}​​
// restored scope chain
fn(); // "bar", foo is still accessible inside fn

A new lexical scope is created and added to the scope chain when the function is executed.

Basically all identifiers (names) of function arguments, variables declared with var and functions declared with the function statement, are bound as properties of a new object created behind the scenes, just before the function itself executes (when controls enters this new execution context).

This object is not accessible through code, is called the Variable Object, for example:

var x = 10, y = 10;   // Step 1

(function () {        // Step 2
  var x, y; 

  x = 30;             // Step 4
  y = 30; 

  alert(x); // 30
  alert(y); // 30
})();                 // Step 3

alert(x); // 10       // Step 5
alert(y); // 10

In the Step 1, again as in my first example, the x and y variables are declared and they are part of the first object in the scope chain, the global object.

In the Step 2, a new function object is created, the parent scope is stored in this moment, into the [[Scope]] of that function, containing now x and y.

In the Step 3, the function is invoked, starting the Variable Instantiation process, which creates a new object in the scope chain, containing the locally scoped x and y variables declared inside this new function, the scope chain at this moment looks like this:

  parent scope           Variable Object
   ________              _______________
  | x = 10 | <--------- | x = undefined |
  | y = 10 |            | y = undefined | 
   ¯¯¯¯¯¯¯¯              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 

Then in the Step 4, the assignment of x and y is done, but since the new lexical scope has been created, it doesn't affect the outer values.

  parent scope           Variable Object
   ________              ________
  | x = 10 | <--------- | x = 30 |
  | y = 10 |            | y = 30 | 
   ¯¯¯¯¯¯¯¯              ¯¯¯¯¯¯¯¯ 

And finally, in the Step 5, the function ends and the scope chain is restored to its original state.

   ________ 
  | x = 10 |
  | y = 10 |
   ¯¯¯¯¯¯¯¯ 

Recommended lectures:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文