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:
'with' n'est pas l'un des' bon parts' pour une raison. –