J'essaie de trier mes réflexions sur le fonctionnement de bind () de javascript.
Je vois que si je le fais
var f = function (a) { ... }
var g = f.bind(obj);
g(1)
alors f est appelé avec obj
comme this
et 1
comme a
.
Ce que je pensais être g est une fonction wrapper autour de f.
Mais quand je fais
var f = function (a) { ... }
var g = f.bind(obj);
g.call(1)
alors f est appelé avec 1
comme this
et a
non défini.
Il semble donc que g n'est pas seulement un simple wrapper, mais call
différencie en quelque sorte les fonctions normales et liées.
Une autre chose est que je ne peux pas appliquer une fonction plus de fois.
var f = function (a) { ... }
var g = f.bind(obj);
var h = g.bind(1);
h();
Ensuite, f est appelé avec obj
comme this
et a
non défini.
Quelle est la cause de ce comportement?
Modifier
Les constructions de cette question sont en fait incorrectes, voir la réponse acceptée à quoi elles devraient ressembler (en général, je n'ai pas remarqué que call
et bind
ont toujours besoin de l'argument context comme premier argument).
Une fois que vous avez lié un objet à une fonction avec bind
, vous ne pouvez pas le remplacer. C'est clairement écrit dans les spécifications, comme vous pouvez le voir dans documentation MDN :
"La fonction bind () crée une nouvelle fonction (une fonction liée) avec le même corps de fonction (propriété d'appel interne en termes ECMAScript 5) que la fonction sur laquelle elle est appelée (la fonction cible de la fonction liée) avec le cette valeur est liée au premier argument de bind (), qui ne peut pas être remplacé. "
Cela signifie aussi si vous le faites:
g.call(1);
Vous obtiendrez obj
sous la forme this
, et non 1
- sur les navigateurs qui suivent les spécifications.
Vous pouvez bien sûr lier plusieurs arguments, donc:
var sum = function(a, b, c) { return a + b + c };
var sumAB = sum.bind(null, 1, 5);
var sumC = sumAB.bind(null, 2);
console.log(sumC());
Mais l'objet de contexte sera toujours celui spécifié avec le premier bind
, car il ne peut pas être remplacé.
Juste pour éviter toute confusion, le premier argument de call est l'objet contextuel (this
), alors vous aurez le reste de l'argument.
Ça veut dire:
var obj = { foo: function(bar) { console.log(bar) } };
obj.foo('hello');
// equivalent to:
var foo = obj.foo;
foo.call(obj, 'hello');
J'espère que ça aide.
Vous n'avez jamais passé d'arguments - vous ne définissez que le contexte. Le premier argument de call
est reçu en tant que contexte (this
), et les arguments 2 et suivants sont reçus en tant qu'arguments 1 et suivants de la fonction appelée. Pendant ce temps, bind
crée une nouvelle fonction avec un nouveau contexte - des arguments sont passés lors de son appel.
Voici les moyens de passer 1
as function f
's argument a
suite à votre premier bloc de code:
f( 1 );
g( 1 );
g.call( this, 1 );
g.apply( this, [ 1 ] );