Domanda

Da: http://ejohn.org/apps/learn/#2

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

Qualcuno può dirmi il motivo per cui la seconda di ritorno è necessario (prima fn.apply)?

Inoltre, qualcuno può spiegare perché args.concat è necessaria? Perché non è vero essere riscritto come:

fn.apply(object, args)

anziché

return fn.apply(object,
          args.concat(Array.prototype.slice.call(arguments)));
È stato utile?

Soluzione

Il secondo ritorno è necessaria perché altrimenti perderemo qualsiasi valore restituito dalla funzione legata.

Si può già sapere questo, ma non fa male a menzione. Se non avvolgere fn.apply all'interno di un'altra funzione, quindi stiamo chiamando direttamente la funzione fn che è sub-ottimale, come bind è solo dovrebbe impostare il contesto di esecuzione (cosa dovrebbe this consultare all'interno della funzione), e non è invoke .

metodi JavaScript può essere invocato chiamando il metodo call o apply su di loro. Ecco un piccolo esempio:

function example() {
    alert("useless example");
}

example.apply() // or example.call(), alerts "useless example";

La funzione esterna nella legatura di Prototype () dovrebbe funzionare come un involucro invisibile intorno alla funzione legato. Così tutti gli argomenti che vengono passati al wrapper devono essere passati alla funzione legata pure, e deve restituire alcun valore restituito dalla funzione rilegati, che è il motivo per cui l'istruzione return è lì.

Il motivo per fare args.concat all'interno fn.apply è diverso e non è facoltativa. bind nel prototipo consente di anteporre gli argomenti alla funzione limite.

args rappresenta gli argomenti che sono stati passati quando abbiamo chiamato bind sulla funzione. arguments rappresenta gli argomenti che sono stati passati quando abbiamo chiamato la funzione limite. Stiamo fondamentalmente concatenazione di due array lì.

Da nell'esempio precedente:

var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49

// arguments that our example() function receives => 12, 23, 36, 49

Altri suggerimenti

Old post, ma un approccio più nuovo;)

Function.prototype.bind = function(){
    var fn = this, 
    context = arguments[0], 
    args = Array.prototype.slice.call(arguments, 1);
    return function(){
        return fn.apply(context, args.concat([].slice.call(arguments)));
    }
}

obj = {'abc':'x'};
var func = function() {
  console.log(arguments);
  alert(this.abc);
}
var x = func.bind(obj);

console.log(x(1,2,3));

Questo è un ottimo esempio per spiegare. Eseguire e controllare il registro di console. Poi modificare il codice per lasciare fuori

[].slice.call(arguments)

Si vedrà che la console.log dell'esecuzione di x (1,2,3) non viene visualizzato gli argomenti più. Questo è perché gli oggetti gli argomenti è una variabile locale all'interno di tutte le funzioni. Questo potrebbe sembrare un po 'di confusione, ma cosa vuol dire è fondamentalmente:

var x = func.bind(obj,1,2,3);

Consegna questa funzione internamente:

function() {
    return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}

Così è più di un modello per la funzione.

Quando non ora correre come:

x(4,5,6)

Questa sarà Ran:

fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))

con argomenti speciali oggetto = {0: 4,1: 5,2: 6}, che può essere convertito in un array usando [] .slice.call dove argomento è un oggetto locale, che viene automaticamente provvisto sia assegnato durante l'invocazione della funzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top