Appels de fonction
Les fonctions ne sont qu'un type d'objet.
Tous les objets Function ont des méthodes d' appel et d' application qui exécutent l'objet Function auquel ils sont appelés.
Lorsqu'il est appelé, le premier argument de ces méthodes spécifie l'objet qui sera référencé par le thismot clé lors de l'exécution de la fonction - si c'est nullou undefined, l'objet global window, est utilisé pour this.
Ainsi, appeler une fonction ...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
... avec des parenthèses - foo()- est équivalent à foo.call(undefined)ou foo.apply(undefined), ce qui est en fait identique à foo.call(window)ou foo.apply(window).
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Des arguments supplémentaires à callsont passés comme arguments à l'appel de fonction, tandis qu'un seul argument supplémentaire à applypeut spécifier les arguments de l'appel de fonction en tant qu'objet de type tableau.
Ainsi, foo(1, 2, 3)est équivalent à foo.call(null, 1, 2, 3)ou foo.apply(null, [1, 2, 3]).
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
Si une fonction est une propriété d'un objet ...
var obj =
{
whereAmI: "obj",
foo: foo
};
... accéder à une référence à la Fonction via l'objet et l'appeler entre parenthèses - obj.foo()- est équivalent à foo.call(obj)ou foo.apply(obj).
Cependant, les fonctions détenues comme propriétés d'objets ne sont pas "liées" à ces objets. Comme vous pouvez le voir dans la définition objci-dessus, puisque les fonctions ne sont qu'un type d'objet, elles peuvent être référencées (et peuvent donc être passées par référence à un appel de fonction ou renvoyées par référence à partir d'un appel de fonction). Lorsqu'une référence à une fonction est passée, aucune autre information sur l' endroit où il a été passé de se fait avec elle, ce qui explique pourquoi les éléments suivants se produit:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
L'appel à notre référence Function baz, ne fournit aucun contexte pour l'appel, il est donc en fait le même que baz.call(undefined), donc thisfinit par faire référence window. Si nous voulons bazsavoir à quoi il appartient obj, nous devons d'une manière ou d'une autre fournir ces informations lors de l' bazappel, c'est là que le premier argument de callou applyet les fermetures entrent en jeu.
Chaînes de portée
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
Lorsqu'une fonction est exécutée, elle crée une nouvelle étendue et a une référence à toute étendue englobante. Lorsque la fonction anonyme est créée dans l'exemple ci-dessus, elle fait référence à l'étendue dans laquelle elle a été créée, qui est bindl'étendue de. C'est ce qu'on appelle une «fermeture».
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
Lorsque vous essayez d'accéder à une variable, cette "chaîne de portée" est parcourue pour trouver une variable avec le nom donné - si la portée actuelle ne contient pas la variable, vous regardez la portée suivante de la chaîne, et ainsi de suite jusqu'à ce que vous atteigniez la portée mondiale. Lorsque la fonction anonyme est renvoyée et bindtermine son exécution, la fonction anonyme a toujours une référence à bindla portée de ', donc bindla portée de' ne disparaît pas '.
Compte tenu de tout ce qui précède, vous devriez maintenant être en mesure de comprendre comment fonctionne la portée dans l'exemple suivant, et pourquoi la technique pour passer une fonction autour de "pré-lié" avec une valeur particulière thisaura quand elle sera appelée fonctionne:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};