如果“与"Javascript 中的语句创建了一个新的作用域,为什么这个闭包不包含新的“x"?每次都在新的范围内? [英] If the "with" statement in Javascript creates a new scope, why does this closure doesn't contain the new "x" in new scope each time?

查看:14
本文介绍了如果“与"Javascript 中的语句创建了一个新的作用域,为什么这个闭包不包含新的“x"?每次都在新的范围内?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果 Javascript 中的 with 语句创建了一个新的范围,那么点击链接是否应该显示不同的 x ,它们在不同的范围内?没有.

ha link 1<a href="#" id="link2">ha 链接 2</a><a href="#" id="link3">ha 链接 3</a><a href="#" id="link4">ha 链接 4</a><a href="#" id="link5">ha 链接 5</a><script type="text/javascript">对于 (i = 1; i <= 5; i++) {with({foo:"bar"}) {var x = i;document.getElementById('link' + i).onclick = function() { alert(x);返回假;}}}

解决方案

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

for (var i = 1; i <= 5; i++) {与({x:i}){document.getElementById('link' + i).onclick = function() {警报(x);返回假;};}}

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

var x = 10, y = 10;//步骤1with ({x: 20}) {//步骤 2无功x = 30,y = 30;//第 3 步警报(x);//30警报(y);//30}警报(x);//10警报(y);//30

在第 1 步中,声明了 xy 变量,它们是作用域链中第一个对象(全局对象)的一部分.

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

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

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

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

y 标识符也被解析,但在链中的第一个对象上找不到,所以继续查找,在最后一个对象上找到它,赋值后的作用域链看起来像这样:

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

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

<前>________|x = 10 ||y = 30 |¯¯¯¯¯¯¯¯

稍微展开说一下功能吧.

当一个函数被创建时,它的当前父作用域被绑定,对于例子:

var fn;//增加作用域链与 ({foo: "bar"}) {fn = function () {//创建函数返回 foo;};}//恢复作用域链fn();//"bar", foo 仍然可以在 fn 内部访问

一个新的词法作用域在函数执行时被创建并添加到作用域链中.

基本上所有函数参数的标识符(名称)、用 var 声明的变量和用 function 语句声明的函数,都绑定为在后面创建的新对象的属性场景,就在函数本身执行之前(当控件进入这个新的执行上下文).

这个对象不能通过代码访问,称为变量对象,例如:

var x = 10, y = 10;//步骤1(function () {//步骤 2变量 x, y;x = 30;//步骤4y = 30;警报(x);//30警报(y);//30})();//第 3 步警报(x);//10//步骤 5警报(y);//10

在第 1 步中,同样在我的第一个示例中,声明了 xy 变量,它们是作用域链中第一个对象的一部分,即全局对象.

在Step 2中,创建了一个新的函数对象,此时父作用域被存储,放入那个函数的[[Scope]]中,现在包含xy.

在第 3 步中,调用该函数,开始变量实例化 进程,它在作用域链中创建一个新对象,包含在这个新函数中声明的局部作用域xy 变量,此时作用域链看起来像这样:

<前>父作用域变量对象________ ______________|x = 10 |<--------- |x = 未定义 ||y = 10 ||y = 未定义 |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

然后在Step 4中,完成了xy的赋值,但是由于新的词法作用域已经创建,所以不影响外部值.

<前>父作用域变量对象________ ________|x = 10 |<--------- |x = 30 ||y = 10 ||y = 30 |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

最后,在第 5 步,函数结束,作用域链恢复到原来的状态.

<前>________|x = 10 ||y = 10 |¯¯¯¯¯¯¯¯

推荐讲座:

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>

解决方案

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:

这篇关于如果“与"Javascript 中的语句创建了一个新的作用域,为什么这个闭包不包含新的“x"?每次都在新的范围内?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆