2010-04-30 4 views
3

Si l'instruction with en Javascript crée une nouvelle portée, ne devrait pas cliquer sur les liens montrent un différent x qui sont dans différentes portées? Ce n'est pas le cas.Si l'instruction "with" dans Javascript crée une nouvelle portée, pourquoi cette fermeture ne contient-elle pas à chaque fois le nouveau "x" dans la nouvelle portée?

<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> 
+1

'with' n'est pas l'un des' bon parts' pour une raison. –

Répondre

27

La déclaration with ne crée pas une pleine nouvelle portée lexicale, il introduit tout un objet en face de la chaîne de portée, par exemple, si vous capturez la variable i, il sera work:

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

Permettez-moi de l'expliquer mieux avec un autre exemple:

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 

Dans l'étape 1, le x et y variables sont déclarées et font partie du premier objet de la chaîne de portée, l'objet global.

Dans l'étape 2, un nouvel objet ({x:20}) est introduit dans la chaîne de portée par la déclaration with, maintenant la chaîne de portée ressemble à ceci:

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

Dans l'étape 3, une autre déclaration var est exécuté, mais cela n'a aucun effet car comme je l'ai déjà dit, seules les fonctions créent une portée lexicale complète.

La déclaration var n'a pas d'effet, mais la cession a, donc lorsque la variable x est résolu, est atteint sur le premier objet sur la chaîne de portée, celle que nous avons introduit à l'aide with.

L'identifiant y est également résolu, mais il ne se trouve pas sur le premier objet dans la chaîne, de sorte que la recherche continue, et trouve le dernier objet, la chaîne de portée après les missions se présente comme suit:

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

a la fin du compte with, la chaîne de portée est finalement restaurée:

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

Edit: Permettez-moi d'un peu et parler des fonctions.

Lorsqu'un function is created son champ d'application parent actuel est lié, par exemple:

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 

Un nouveau champ lexical est créé et ajouté à la chaîne de portée lorsque la fonction est exécutée. Fondamentalement, tous les identifiants (noms) des arguments de fonction, variables déclarées avec var et les fonctions déclarées avec l'instruction function, sont liés comme les propriétés d'un nouvel objet créé en coulisses, juste avant que la fonction elle-même s'exécute (quand les contrôles entrent dans cette nouveau execution context).

Cet objet est pas accessible par code, est appelé le objet variable, par exemple:

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 

Dans l'étape 1, encore une fois comme dans mon premier exemple, les variables x et y sont déclarées et ils font partie du premier objet de la chaîne de portée, l'objet global.

Dans l'étape 2, un nouvel objet de fonction est créé, la portée parent est stockée dans ce moment, dans [[Scope]] de cette fonction, contenant maintenant x et y.

Dans l'étape 3, la fonction est appelée, en commençant le processus Variable Instantiation, ce qui crée un nouvel objet dans la chaîne de portée, contenant le local Variables déclarées x et y déclarées dans cette nouvelle fonction, la chaîne de portée à ce moment semble comme ceci:

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

ensuite à l'étape 4, l'affectation des x et y est fait, mais étant donné que le nouveau champ lexical a été créé, il ne porte pas atteinte aux valeurs extérieures.

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

Enfin, à l'étape 5, la fonction se termine et la chaîne de portée est restaurée dans son état d'origine.

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

conférences recommandées:

+0

alors la fermeture contiendra cet "objet" comme la plus grande portée? Est-ce une sorte de chaîne de portée hybride ... ou est-ce juste une chaîne de portée normale? donc si nous avons imbriqué "avec" et invoquer des fonctions anonymes à l'intérieur de ces "avec" imbriqués, nous pouvons avoir une chaîne de portée qui ressemble à "portée, portée, portée, portée, objet, portée, objet, portée, objet, portée" ? (la dernière portée est la plus grande portée) –

+0

@Jian Lin: J'ai étendu ma réponse pour parler des fonctions, et comment la nouvelle portée lexicale est créée. – CMS

Questions connexes