Considérons ce code javascript:
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
En exécutant ce code je reçois "A". Ce comportement fait-il partie de la spécification javascript et puis-je m'appuyer dessus?
Oui c'est prévu et par conception.
Votre question est fondamentalement la suivante: foo
fait-il référence bar
en tant que pointeur ou référence dans une autre langue?
La réponse est non: la valeur de bar
au moment de l'affectation est affectée à foo
.
Dans d'autres exemples, rien n'a été passé par valeur; tout a été passé par référence.
bar et foo sont les deux pointeurs
Tous les vars/descripteurs d'objets non primitifs en javascript sont des pointeurs; les pointeurs sont natifs de javascript, ils sont la valeur par défaut.
var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar; //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); }; //bar points to function2
foo(); //foo is still a pointer to function1
Vous rencontrerez des erreurs cachées et des bugs si vous pensez qu'ils sont des copies. Surtout si vous travaillez avec des objets complexes. Par exemple
function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john
Pour vraiment copier une javascript non primitive en javascript, il faut plus de travail que juste a = b .
function person(name){ this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__ //useful in some cases
john.name = "jack"
backup.name //john
Je suis un peu en retard mais je pensais quand même donner une réponse et préciser quelque chose.
Il est préférable de ne pas penser en termes de pointeurs et de références mémoire lors de la discussion sur les éléments internes de JavaScript (ou ECMAScript) lors du traitement des spécifications. Les variables sont des enregistrements d'environnement internes. Elles sont stockées et référencées par nom, et non par adresse mémoire. Dans votre déclaration d'affectation, en interne et par conception, vous recherchez le nom de l'enregistrement d'environnement ("foo" ou "bar") et vous affectez la valeur à cet enregistrement.
Alors,
var bar = function () { alert("A"); }
attribue à l’enregistrement d’environnement "bar" la valeur (fonction anonyme).
var foo = bar;
appelle en interne GetValue ("bar") qui récupère la valeur associée à l'enregistrement "bar" puis associe cette valeur à l'enregistrement "foo". Par conséquent, la valeur initiale de bar peut toujours être utilisée car elle est maintenant associée à foo.
Parce que les références JavaScript par chaîne et non par adresse mémoire constituent précisément la raison pour laquelle vous pouvez procéder comme suit:
someObject["someProperty"]
qui recherche la valeur en fonction du nom de la propriété.
Vous affectez la valeur d'une fonction anonyme à une variable et non à un pointeur.
Si vous voulez jouer avec des pointeurs, vous pouvez utiliser des objets passés par référence, pas par copie.
Voici quelques exemples:
"obj2" est une référence à "obj1", vous modifiez "obj2" et "obj1" est modifié. Il va alerter false
.
var obj1 = {prop:true},
obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);
"prop" pointe sur une propriété qui n'est pas un objet, "prop" n'est pas un pointeur sur cet objet mais une copie. Si vous modifiez "prop", "obj1" n'est pas modifié. Il va alerter true
var obj1 = {prop:true},
prop = obj1.prop;
prop = false;
alert(obj1.prop);
"obj2" est une référence à la propriété "subObj" de "obj1". si "obj2" est changé, "obj1" est changé. Il va alerter false
.
var obj1 = {subObj:{prop:true}},
obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
Oui, il n'y a rien de spécial sur le fait que les variables se réfèrent à des fonctions, il n'y a pas d'aliasing impliqué.
var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
Oui, c'est le comportement correct.
//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
Ce ne sont pas des pointeurs de fonction (et il n’ya pas de pointeur dans JS de manière native). Les fonctions dans JS peuvent être anonymes et sont des objets de première classe. Par conséquent
function () { alert("A"); }
crée une fonction anonyme qui alerte "A" lors de l'exécution;
var bar = function () { alert("A"); };
assigner cette fonction à bar;
var foo = bar;
assigne foo à bar, qui est la fonction "A".
bar = function () { alert("B"); };
rebind bar à une fonction anonyme "B". Cela n'affectera pas foo ou l'autre fonction "A".
foo();
Appelez la fonction enregistrée dans foo, qui est la fonction "A".
En fait, dans les langues où il y a des points de fonction, par exemple C cela n’affectera pas non plus foo
. Je ne sais pas où vous avez eu l'idée d'obtenir "B" lors de la réaffectation.
void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
Ceci assigne une variable à une fonction non nommée, pas un pointeur sur une fonction
Oui, vous avez créé un pointeur sur la fonction "A" d'origine. Lorsque vous réaffectez la barre, vous réaffectez elle, mais vous laissez toujours des références à l'ancienne fonction seule.
Donc, pour répondre à votre question, oui, vous pouvez vous y fier.
Je voudrais juste ajouter que cela fonctionne également pour les fonctions nommées prédéfinies:
function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();
Cela fera la même chose, indiquant que les noms de fonctions agissent comme des noms de tableaux (pointeurs).
Pour chaque FunctionDeclaration f dans le code, dans l'ordre du texte source, procédez comme suit:
Soit fn l'identifiant dans FunctionDeclaration f.
Soit fo le résultat de l'instanciation de FunctionDeclaration f comme décrit dans l'Article 13.
Laissez funcAlreadyDeclared être le résultat de l’appel de la méthode concrète HasBinding d’env en transmettant fn en tant qu’argument.
Si funcAlreadyDeclared est défini sur false, appelez la méthode concrète CreateMutableBinding d’env en transmettant fn et configurableBindings en tant qu’arguments.
Références