如果“具有”语句在Javascript中创建一个新的作用域,为什么下面的代码不能按预期工作? (闭包不每次在新范围中包含新的“x”), [英] If the "with" statement in Javascript creates a new scope, why does the following code not work as expected? (the closure doesn't contain the new "x" in new scope each time)

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

问题描述

如果JavaScript中的与语句创建了一个新作用域,则不应该单击链接显示不同的 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>


解决方案

c $ c>语句不会创建一个完整的新词法作用域,它只是在作用域链前面引入了一个对象,例如,如果捕获 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 y 变量被声明,它们是范围链中全局对象的第一个对象的一部分。



在步骤2中,通过 {x:20} c>语句,现在范围链看起来像这样:

 
________ ________
| x = 10 | < --------- x = 20 |
| y = 10 |在步骤3中,另一个 code> var
语句被执行,但它没有效果,因为正如我前面所说的,只有函数创建一个完整的词法作用域。



var 语句没有效果,但是赋值语句有效,因此当 x 在范围链上的第一个对象,我们使用与引入的对象。



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

 
________ ________
| x = 10 | < --------- x = 30 |
| y = 30 |当时,

>与语句结束,范围链终于恢复:

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

编辑
让我展开



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

  var fn; 
// extends scope chain
with({foo:bar}){
fn = function(){//创建函数
return foo;
};
}
//恢复范围链
fn(); //bar,foo仍然可以在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 //步骤5
alert(y); // 10

在第1步中,与第一个例子一样, x y 变量被声明,它们是范围链中全局对象的第一个对象的一部分。



在步骤2中,创建一个新的函数对象,父范围存储在这个时候,到该函数的[[Scope]],包含现在 x y



在第3步中,函数被调用, 变量实例化过程,它在范围链中创建一个新对象,包含在此新函数中声明的局部范围的 x y 变量,此时的范围链看起来像这样:

 
父作用域变量对象
________ _______________
| x = 10 | < --------- x = undefined |
| y = 10 | | y = undefined |
¯¯¯¯¯¯¯¯¯¯¯¯¯¯

然后在步骤4中,完成 x y 的分配,但由于已创建新的词汇作用域,它不影响外部值。

 
父作用域变量对象
________ ________
| 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天全站免登陆