web-dev-qa-db-fra.com

Lier plus d'arguments d'une fonction déjà liée en Javascript

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).

28
Martin Pecka

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.

45
ZER0

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 ] );
3
Barney