javascript call - ¿Cuál es la diferencia entre llamar y aplicar?




tutorial codigo (17)

Para responder a la parte sobre cuándo usar cada función, use apply si no conoce la cantidad de argumentos que pasará, o si ya están en una matriz o un objeto similar a una matriz (como el objeto de arguments para reenviar su propia argumentos. Utilice call contrario, ya que no hay necesidad de envolver los argumentos en una matriz.

f.call(thisObject, a, b, c); // Fixed number of arguments

f.apply(thisObject, arguments); // Forward this function's arguments

var args = [];
while (...) {
    args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments

Cuando no estoy pasando ningún argumento (como su ejemplo), prefiero call ya que estoy llamando a la función. apply implicaría que está aplicando la función a los argumentos (no existentes).

No debería haber diferencias de rendimiento, excepto si utiliza y ajusta los argumentos en una matriz (por ejemplo, f.apply(thisObject, [a, b, c]) lugar de f.call(thisObject, a, b, c) ). No lo he probado, por lo que podría haber diferencias, pero sería muy específico del navegador. Es probable que la call sea ​​más rápida si aún no tiene los argumentos en una matriz y la apply es más rápida si la tiene.

¿Cuál es la diferencia entre usar call y apply para invocar una función?

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

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

¿Existen diferencias de rendimiento entre los dos métodos mencionados? ¿Cuándo es mejor usar call over apply y viceversa?


Aquí hay una buena mnemotécnica. A pply usa A rrays y A lways toma uno o dos Argumentos. Cuando usa C, todo lo que tiene que hacer para calcular el número de argumentos.


Otro ejemplo con Call, Apply y Bind. La diferencia entre Call y Apply es evidente, pero Bind funciona así:

  1. Bind devuelve una instancia de una función que puede ser ejecutada
  2. El primer parámetro es " esto "
  3. El segundo parámetro es una lista de argumentos separados por comas (como Call )

}

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
*/

Si bien este es un tema antiguo, solo quería señalar que .call es un poco más rápido que .apply. No te puedo decir exactamente por qué.

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

[ UPDATE! ]

Douglas Crockford menciona brevemente la diferencia entre los dos, lo que puede ayudar a explicar la diferencia de rendimiento ... http://youtu.be/ya4UHuXNygM?t=15m52s

Apply toma una serie de argumentos, mientras que Call toma cero o más parámetros individuales. Ah hah

.apply(this, [...])

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


Me gustaría mostrar un ejemplo, donde se usa el argumento 'valueForThis':

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] 

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


Sigue un extracto de Closure: The Definitive Guide por Michael Bolin . Puede parecer un poco largo, pero está saturado con mucha información. Del "Apéndice B. Conceptos de JavaScript frecuentemente mal entendidos":

A qué se refiere this cuando se llama una función

Cuando se llama a una función de la forma foo.bar.baz() , el objeto foo.bar se conoce como el receptor. Cuando se llama a la función, es el receptor el que se utiliza como 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);

Si no hay un receptor explícito cuando se llama a una función, entonces el objeto global se convierte en el receptor. Como se explica en "goog.global" en la página 47, la ventana es el objeto global cuando se ejecuta JavaScript en un navegador web. Esto lleva a un comportamiento sorprendente:

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

Aunque obj.addValues y f refieren a la misma función, se comportan de manera diferente cuando se les llama porque el valor del receptor es diferente en cada llamada. Por esta razón, cuando se llama a una función que se refiere a this , es importante asegurarse de que tendrá el valor correcto cuando se llame. Para ser claros, si this no fuera referenciado en el cuerpo de la función, entonces el comportamiento de f(20) y obj.addValues(20) sería el mismo.

Debido a que las funciones son objetos de primera clase en JavaScript, pueden tener sus propios métodos. Todas las funciones tienen los métodos call() y apply() que permiten redefinir el receptor (es decir, el objeto al que se refiere) al llamar a la función. Las firmas del método son las siguientes:

/**
* @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;

Tenga en cuenta que la única diferencia entre call() y apply() es que call() recibe los parámetros de la función como argumentos individuales, mientras que apply() recibe como una única matriz:

// 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]);

Las siguientes llamadas son equivalentes, ya que f y obj.addValues refieren a la misma función:

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

Sin embargo, dado que ni call() ni apply() utilizan el valor de su propio receptor para sustituir el argumento del receptor cuando no está especificado, lo siguiente no funcionará:

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

El valor de this nunca puede ser null o undefined cuando se llama a una función. Cuando null o undefined se proporciona como el receptor para call() o apply() , el objeto global se utiliza como el valor para el receptor. Por lo tanto, el código anterior tiene el mismo efecto secundario indeseable de agregar una propiedad denominada value al objeto global.

Puede ser útil pensar que una función no tiene conocimiento de la variable a la que está asignada. Esto ayuda a reforzar la idea de que el valor de esto se vinculará cuando se llame a la función en lugar de cuando se defina.

Fin del extracto.


Llamar y aplicar ambos se utilizan para forzar this valor cuando se ejecuta una función. La única diferencia es que la call toma n+1 argumentos donde 1 es this y 'n' arguments . apply toma solo dos argumentos, uno es el otro es la matriz de argumentos.

La ventaja que veo en la apply sobre call es que podemos delegar fácilmente una llamada de función a otra función sin mucho esfuerzo;

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

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

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

Observe la facilidad con la que sayHello hello a sayHello uso de sayHello , pero con " call es muy difícil de lograr.


La diferencia es que la apply permite invocar la función con arguments como una matriz; call requiere que los parámetros se enumeren explícitamente. Un mnemotécnico útil es " A para un rray y C para c omma".

Ver la documentación de MDN en apply y call .

Pseudo sintaxis:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

También existe, a partir de ES6, la posibilidad de spread la matriz para usar con la función de call , puede ver las compatibilidades here .

Código de muestra:

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator


A pesar de que call y apply es lo mismo, creo que hay al menos un lugar donde no se puede usar la call pero solo se puede apply . Esto es cuando desea admitir la herencia y desea llamar al constructor.

Aquí hay una función que le permite crear clases que también admiten la creación de clases extendiendo otras clases.

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

Podemos diferenciar los métodos de llamada y aplicación de la siguiente manera.

LLAMADA: Una función con argumento proporciona individualmente. Si conoce los argumentos que deben pasarse o no hay ningún argumento para aprobar, puede usar call.

APLICAR: llamar a una función con el argumento proporcionado como una matriz. Puede usar aplicar si no sabe cuántos argumentos pasarán a la función.

Hay una ventaja de usar aplicar sobre llamada, no necesitamos cambiar el número de argumentos, solo podemos cambiar una matriz que se pasa.

No hay gran diferencia en el rendimiento. Pero podemos decir que la llamada es un poco más rápida que comparar para aplicar porque una matriz necesita evaluar el método de aplicación.


A veces es útil que un objeto tome prestada la función de otro, lo que significa que el objeto prestado simplemente ejecuta la función prestada como si fuera su propia función.

Un pequeño ejemplo 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

Estos métodos son muy útiles para dar funcionalidad temporal a los objetos.


De los documentos MDN en Function.prototype.apply () :

El método apply () llama a una función con un determinado valor y argumentos proporcionados como una matriz (o un objeto similar a una matriz).

Sintaxis

fun.apply(thisArg, [argsArray])

De los documentos MDN en Function.prototype.call () :

El método call () llama a una función con un determinado valor y argumentos proporcionados individualmente.

Sintaxis

fun.call(thisArg[, arg1[, arg2[, ...]]])

Desde Function.apply y Function.call en JavaScript :

El método apply () es idéntico a call (), excepto que apply () requiere una matriz como segundo parámetro. La matriz representa los argumentos para el método de destino.

Ejemplo de código:

var doSomething = function() {
    var arr = [];
    for(i in arguments) {
        if(typeof this[arguments[i]] !== 'undefined') {
            arr.push(this[arguments[i]]);
        }
    }
    return arr;
}

var output = function(position, obj) {
    document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>';
}

output(1, doSomething(
    'one',
    'two',
    'two',
    'one'
));

output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [
    'one',
    'two',
    'two',
    'one'
]));

output(3, doSomething.call({one : 'Steven', two : 'Jane'},
    'one',
    'two',
    'two',
    'one'
));

Véase también este violín .


La diferencia fundamental es que call() acepta una lista de argumentos , mientras que apply() acepta una única serie de argumentos .


K. Scott Allen tiene una buena reseña al respecto.

Básicamente, difieren en cómo manejan los argumentos de la función.

El método apply () es idéntico a call (), excepto que apply () requiere una matriz como segundo parámetro. La matriz representa los argumentos para el método de destino ".

Asi que:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);


La diferencia es que call() toma los argumentos de la función por separado, y apply() toma los argumentos de la función en una matriz.


Intente usar SQLITE_STATIC lugar de SQLITE_TRANSIENT para esas inserciones.

SQLITE_TRANSIENT hará que SQLite copie los datos de la cadena antes de regresar.

SQLITE_STATIC le dice que la dirección de memoria que le dio será válida hasta que se haya realizado la consulta (que en este bucle siempre es el caso). Esto le ahorrará varias operaciones de asignación, copia y desasignación por bucle. Posiblemente una gran mejora.





javascript performance function dynamic