usar - script type= text/javascript src=




Qual é a diferença entre ligar e aplicar? (14)

Resumo:

Ambos call() e apply() são métodos que estão localizados em Function.prototype . Portanto, eles estão disponíveis em todos os objetos de função através da cadeia de protótipos. Ambos call() e apply() podem executar uma função com um valor especificado do this .

A principal diferença entre call() e apply() é a maneira que você tem que passar argumentos nele. Em ambos, call() e apply() você passa como primeiro argumento o objeto que você quer que seja o valor como this . Os outros argumentos diferem da seguinte maneira:

  • Com call() você tem que colocar os argumentos normalmente (a partir do segundo argumento)
  • Com apply() você tem que passar em array de argumentos.

Exemplo:

let obj = {
  val1: 5,
  val2: 10
}

const summation = function (val3, val4) {
  return  this.val1 + this.val2 + val3 + val4;
}

console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array


console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually

Por que eu precisaria usar essas funções?

this valor pode ser complicado, por vezes, em javascript. O valor this determinado quando uma função é executada não quando uma função é definida. Se nossa função depender de um direito this ligação, podemos usar call() e apply() para reforçar esse comportamento. Por exemplo:

var name = 'unwantedGlobalName';

const obj =  {
  name: 'Willem',
  sayName () { console.log(this.name);}
}


let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable



copiedMethod();
// this is now window, unwantedGlobalName gets logged

copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged

Qual é a diferença entre usar call e apply para invocar uma função?

var func = function() {
  alert('hello!');
};

func.apply(); vs func.call();

Existem diferenças de desempenho entre os dois métodos acima mencionados? Quando é melhor usar o apply call over e vice-versa?


Às vezes, é útil para um objeto emprestar a função de outro objeto, o que significa que o objeto mutuário simplesmente executa a função emprestada como se fosse sua própria.

Um pequeno exemplo de código:

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

}; 

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true); 

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

Esses métodos são muito úteis para dar aos objetos uma funcionalidade temporária.


A diferença é que call() pega os argumentos da função separadamente e apply() pega os argumentos da função em uma matriz.


A diferença fundamental é que call() aceita uma lista de argumentos , enquanto apply() aceita uma única matriz de argumentos .


Aqui está um bom mnemônico. Um pply usa A rrays e A lways leva um ou dois argumentos. Quando você usa C, tudo o que você precisa para calcular o número de argumentos.


Aqui está um pequeno post, escrevi sobre isso:

http://sizeableidea.com/call-versus-apply-javascript/

var obj1 = { which : "obj1" },
obj2 = { which : "obj2" };

function execute(arg1, arg2){
    console.log(this.which, arg1, arg2);
}

//using call
execute.call(obj1, "dan", "stanhope");
//output: obj1 dan stanhope

//using apply
execute.apply(obj2, ["dan", "stanhope"]);
//output: obj2 dan stanhope

//using old school
execute("dan", "stanhope");
//output: undefined "dan" "stanhope"

Chamar e aplicar ambos são usados ​​para forçar this valor quando uma função é executada. A única diferença é que a call recebe n+1 argumentos em que 1 é this e 'n' arguments . apply leva apenas dois argumentos, um é o outro array de argumentos.

A vantagem que vejo em apply over call é que podemos facilmente delegar uma chamada de função para outra função sem muito esforço;

function sayHello() {
  console.log(this, arguments);
}

function hello() {
  sayHello.apply(this, arguments);
}

var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');

Observe a facilidade com que delegamos o hello para sayHello hello usando " apply , mas com a call isso é muito difícil de conseguir.


Diferença entre estes para métodos são, como você deseja passar os parâmetros.

"A para matriz e C para vírgula" é um mnemônico útil.


Embora este seja um tópico antigo, eu só queria ressaltar que o .call é um pouco mais rápido que o .apply. Eu não posso te dizer exatamente por quê.

Veja jsPerf, http://jsperf.com/test-call-vs-apply/3

[ UPDATE! ]

Douglas Crockford menciona brevemente a diferença entre os dois, o que pode ajudar a explicar a diferença de desempenho ... http://youtu.be/ya4UHuXNygM?t=15m52s

Aplicar leva uma matriz de argumentos, enquanto a chamada leva zero ou mais parâmetros individuais! Ah hah!

.apply(this, [...])

.call(this, param1, param2, param3, param4...)


Gostaria de mostrar um exemplo, onde o argumento 'valueForThis' é usado:

Array.prototype.push = function(element) {
   /*
   Native code*, that uses 'this'       
   this.put(element);
   */
}
var array = [];
array.push(1);
array.push.apply(array,[2,3]);
Array.prototype.push.apply(array,[4,5]);
array.push.call(array,6,7);
Array.prototype.push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9] 

** detalhes: http://es5.github.io/#x15.4.4.7 *


Mesmo que call e apply o mesmo, acho que há pelo menos um lugar onde você não pode usar a call mas só pode usar apply . Isso é quando você quer apoiar a herança e quer chamar o construtor.

Aqui está uma função que permite criar classes que também suportam a criação de classes estendendo outras classes.

function makeClass( properties ) {
    var ctor = properties['constructor'] || function(){}
    var Super = properties['extends'];
    var Class = function () {
                 // Here 'call' cannot work, only 'apply' can!!!
                 if(Super)
                    Super.apply(this,arguments);  
                 ctor.apply(this,arguments);
                }
     if(Super){
        Class.prototype = Object.create( Super.prototype );
        Class.prototype.constructor = Class;
     }
     Object.keys(properties).forEach( function(prop) {
           if(prop!=='constructor' && prop!=='extends')
            Class.prototype[prop] = properties[prop];
     });
   return Class; 
}

//Usage
var Car = makeClass({
             constructor: function(name){
                         this.name=name;
                        },
             yourName: function() {
                     return this.name;
                   }
          });
//We have a Car class now
 var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat

var SuperCar = makeClass({
               constructor: function(ignore,power){
                     this.power=power;
                  },
               extends:Car,
               yourPower: function() {
                    return this.power;
                  }
              });
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6

Outro exemplo com Call, Apply e Bind. A diferença entre Call e Apply é evidente, mas Bind funciona assim:

  1. Vincular retorna uma instância de uma função que pode ser executada
  2. Primeiro Parâmetro é ' this '
  3. Segundo parâmetro é uma lista de argumentos separados por vírgulas (como Chamada )

}

function Person(name) {
    this.name = name; 
}
Person.prototype.getName = function(a,b) { 
     return this.name + " " + a + " " + b; 
}

var reader = new Person('John Smith');

reader.getName = function() {
   // Apply and Call executes the function and returns value

   // Also notice the different ways of extracting 'getName' prototype
   var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
   console.log("Apply: " + baseName);

   var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
   console.log("Call: " + baseName);

   // Bind returns function which can be invoked
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/

Podemos diferenciar chamada e aplicar métodos como abaixo

CALL: Uma função com argumento fornece individualmente. Se você conhece os argumentos a serem passados ​​ou não há argumentos para passar, você pode usar a chamada.

APLICAR: Chame uma função com argumento fornecido como uma matriz. Você pode usar apply se não souber quantos argumentos vão passar para a função.

Há uma vantagem de usar o comando over call, não precisamos alterar o número de argumentos apenas podemos alterar um array que é passado.

Não há grande diferença no desempenho. Mas podemos dizer que a chamada é um pouco mais rápida, como comparar para aplicar porque uma matriz precisa avaliar no método apply.


Segue um extrato de Encerramento: O Guia Definitivo de Michael Bolin . Pode parecer um pouco demorado, mas está saturado de muito insight. Do "Apêndice B. Conceitos JavaScript Freqüentemente Entendidos":

O que this se refere quando uma função é chamada

Ao chamar uma função do formato foo.bar.baz() , o objeto foo.bar é chamado de receptor. Quando a função é chamada, é o receptor que é usado como o valor para this :

var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
  for (var i = 0; i < arguments.length; i++) {
    this.value += arguments[i];
  }
  return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);

Se não houver um receptor explícito quando uma função é chamada, o objeto global se torna o receptor. Conforme explicado em "goog.global" na página 47, a janela é o objeto global quando o JavaScript é executado em um navegador da web. Isso leva a um comportamento surpreendente:

var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN

Mesmo que obj.addValues e f refiram-se à mesma função, eles se comportam de maneira diferente quando chamados porque o valor do receptor é diferente em cada chamada. Por esse motivo, ao chamar uma função que se refere a this , é importante garantir que this tenha o valor correto quando for chamado. Para ser claro, se this não fosse referenciado no corpo da função, o comportamento de f(20) e obj.addValues(20) seria o mesmo.

Como as funções são objetos de primeira classe em JavaScript, elas podem ter seus próprios métodos. Todas as funções têm os métodos call() e apply() que permitem redefinir o receptor (isto é, o objeto a que this se refere) ao chamar a função. As assinaturas do método são as seguintes:

/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;

Note que a única diferença entre call() e apply() é que call() recebe os parâmetros da função como argumentos individuais, enquanto apply() recebe como um array único:

// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);

As seguintes chamadas são equivalentes, pois f e obj.addValues referem-se à mesma função:

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

No entanto, como nem call() nem apply() usa o valor de seu próprio receptor para substituir o argumento do receptor quando não é especificado, o seguinte não funcionará:

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

O valor this nunca pode ser null ou undefined quando uma função é chamada. Quando null ou undefined é fornecido como o receptor para call() ou apply() , o objeto global é usado como o valor para o receptor. Portanto, o código anterior tem o mesmo efeito colateral indesejado de adicionar uma propriedade chamada value ao objeto global.

Pode ser útil pensar em uma função como não tendo conhecimento da variável à qual ela é atribuída. Isso ajuda a reforçar a ideia de que o valor disso será vinculado quando a função for chamada, e não quando ela for definida.

Fim do extrato.







dynamic