2011-12-28 9 views
60

¿Puede alguien explicar el contexto para usar los métodos call y apply en Javascript?contexto para usar llamar y aplicar en Javascript?

¿Por qué usar call y apply en lugar de llamar a una función directamente?

+2

[Este lecturas] (https://t.co/BVQPwfqqnO) me ayudó a entender el punto de '' thisArg' cuando se llama a aplicar() 'y' llamada() 'que parece ser el núcleo de tu pregunta. Necesita comprender la primitiva de invocación de función en Javascript –

Respuesta

20

Solo si usa call o apply puede modificar el contexto this dentro de la función.

A diferencia de otros idiomas, en JavaScript this no se refiere al objeto actual, sino al contexto de ejecución y puede establecerlo la persona que llama.

Si se llama a una función utilizando la palabra clave newthis se referirá correctamente al nuevo objeto (dentro de la función constructora) ..

Pero en todos los demás casos - this se referirá al objeto global a menos que establecer explícitamente a través call

+0

. Podría referirse al obj que llama, si usa la sintaxis 'obj.whatever();'. –

+0

La frase "Pero en todos los demás casos, esto se referirá al objeto global a menos que se establezca explícitamente mediante llamada" se debe corregir a lo siguiente: "Pero en todos los demás casos, a menos que se establezca explícitamente mediante llamada, esto se referirá al objeto global si utilizando Ecmascript 3 o Ecmascript 5 (o posterior) en modo no estricto. Sin embargo, en Ecmascript 5 (o posterior) con modo estricto, esto siempre está indefinido si no se establece explícitamente y el motor JS lanzará una excepción cuando acceda a esto. Consulte: http://stackoverflow.com/questions/9822561/why-is-this-in-an-anonymous-function-undefined-when-using-strict –

68

Utiliza call o apply cuando desea pasar un valor this diferente a la función. En esencia, esto significa que desea ejecutar una función como si fuera un método de un objeto particular. La única diferencia entre los dos es que call espera parámetros separados por comas, mientras que apply espera parámetros en una matriz.

Un ejemplo de Mozilla's apply page, en donde están encadenados constructores:

function Product(name, price) { 
    this.name = name; 
    this.price = price; 

    if (price < 0) 
     throw RangeError('Cannot create product "' + name + '" with a negative price'); 
    return this; 
} 

function Food(name, price) { 
    Product.apply(this, arguments); 
    this.category = 'food'; 
} 
Food.prototype = new Product(); 

function Toy(name, price) { 
    Product.apply(this, arguments); 
    this.category = 'toy'; 
} 
Toy.prototype = new Product(); 

var cheese = new Food('feta', 5); 
var fun = new Toy('robot', 40); 

¿Qué Product.apply(this, arguments) hace es la siguiente: El constructor Product se aplica como una función dentro de cada uno de los Food y Toy constructores, y cada uno de estos objetos las instancias se pasan como this. Por lo tanto, cada uno de Food y Toy ahora tiene this.name y this.category propiedades.

+5

solo una pregunta sobre el fragmento de código provisto, por qué Toy's and Food's prototipo es reemplazado por un objeto Producto? – davids

+0

Comentando solo para topar la pregunta de @davids: ¿por qué tenemos que hacer 'Toy.prototype = new Product();'? Probé esto y eliminar esas líneas parece no hacer ninguna diferencia en el resultado final. – adrianp

+6

@davids & @adrianp: es necesario para que los alimentos y los juguetes hereden del producto. Mire este ejemplo: http://jsfiddle.net/Shawn/xNEYf/ Quité 'Toy.prototype = new Product();' pero dejé 'Food.prototype = new Product();' en, entonces ahora Food hereda de Producto, pero Toy no. También agregué un método al prototipo del Producto y lo llamé desde Comida y Juguete para hacer la falta de herencia más obvia (solo abra la consola y ejecute el código, Food puede llamar al método heredado del Producto, pero Toy no puede y arroja un error) . – Shawn

3

Si tiene experiencia con jQuery, sabrá que la mayoría de las funciones utilizan el objeto this. Por ejemplo, collection.each(function() { ... }); Dentro de esta función, "this" se refiere al objeto iterador. Este es un uso posible.

Personalmente he usado .apply() para implementar una cola de solicitudes - Empujo una matriz de argumentos en la cola, y cuando llega el momento de ejecutarla, tomo un elemento, y lo paso como los argumentos para una función de controlador utilizando .apply(), lo que hace que el código sea más limpio, luego si tiene que pasar una matriz de argumentos como primer argumento. Ese es otro ejemplo.

En general, solo tenga en cuenta que esas formas de llamar a una función existen, y es posible que algún día las encuentre convenientes para usarlas para implementar su programa.

6

Utiliza .call() cuando desee que una función se ejecute con un valor this diferente. Establece el valor this según lo especificado, establece los argumentos como se especifica y luego llama a la función. La diferencia entre .call() y solo ejecutar la función es el valor del puntero this cuando se ejecuta la función.Cuando ejecuta la función normalmente, javascript decide cuál será el puntero this (generalmente el contexto global window a menos que se llame a la función como método en un objeto). Cuando usa .call(), especifica exactamente en qué desea que se configure this.

Utiliza .apply() cuando los argumentos que desea pasar a una función están en una matriz. .apply() también puede hacer que una función se ejecute con un valor específico de this. .apply() se usa con más frecuencia cuando tiene una cantidad indeterminada de argumentos que provienen de alguna otra fuente. También se usa para pasar los argumentos de una llamada de función a otra utilizando la variable local especial arguments que contiene una matriz de argumentos que se pasaron a su función actual.

Me resultan útiles las páginas de referencias de MDN para .call() y .apply().

+0

Gracias, lo explicas muy bien. Finalmente comprende el uso del primer argumento. –

0

No puedo pensar en ninguna situación normal en la que configurar thisArg para algo diferente es el propósito de usar apply.

El objetivo de apply es pasar una matriz de valores a una función que quiere esos valores como argumentos.

Ha sido reemplazado en todos los usos diarios por el operador de propagación.

p. Ej.

// Finding the largest number in an array 
`Math.max.apply(null, arr)` becomes `Math.max(...arr)` 

// Inserting the values of one array at the start of another 
Array.prototype.unshift.apply(arr1, arr2); 
// which becomes 
arr1 = [...arr2, ...arr1] 
0

Si usted tiene experiencia con Object Oriented Programming luego llamar y aplicar tendrá sentido si se compara con la herencia y anular las propiedades o métodos/funciones de la clase padre de la clase hija. Que es similar con la llamada en javascript de la siguiente manera:

function foo() { 
    this.helloworld = "hello from foo" 
} 
foo.prototype.print = function() { 
    console.log(this.helloworld) 
} 

foo.prototype.main = function() { 
    this.print() 
} 


function bar() { 
    this.helloworld = 'hello from bar' 
} 
// declaring print function to override the previous print 
bar.prototype.print = function() { 
    console.log(this.helloworld) 
} 

var iamfoo = new foo() 

iamfoo.main() // prints: hello from foo 

iamfoo.main.call(new bar()) // override print and prints: hello from bar 
Cuestiones relacionadas