Function.prototype.apply()

This translation is incomplete. Please help translate this article from English.

Resumen

El método apply() invoca una determinada función asignando explícitamente el objeto this y un arreglo o similar (array like object) como parámetros (arguments) para dicha función.

NOTA: Aunque la sintaxis de esta función es casi idéntica a call(), la diferencia fundamental es que call() acepta una lista de argumentos, mientras que apply() acepta un solo arreglo de argumentos.

Sintaxis

fun.apply(thisArg[, argsArray])

Parámetros

thisArg
El valor del objeto this autilizar dentro de la llamada a fun. Cabe mencionar que éste puede no ser el valor visto por el método: si el método es una función del tipo non-strict mode, nullundefined será reemplazado por el objeto global, y los valores primitivos serán encapsulados.
argsArray
Un objeto similar a un arreglo (array like object), que contiene los parámetros con los que será llamada fun, o nullundefined si ningún argumento es estipulado. Desde la versión 5 de ECMAScript estos parámetros pueden estar en un objeto similar a un arreglo en lugar de un arreglo. Véase browser compatibility para mayor información.

Descripción

Puede estipularse un objeto this diferente al llamar una función. this se refiere al objeto actual, el objeto haciendo la llamada. Con apply, puede escribirse un método una vez y heredarlo a otro objeto, sin necesidad de reescribir el método para adecuarlo al nuevo objeto.

apply es muy similar a call(), excepto por el tipo de argumentos que soporta. Puede utilizarse un arreglo de parámetros en lugar de un conjunto de pares nombre-valor. Con apply, puede utilizarse un arreglo literal, por ejemplo, fun.apply(this, ['eat', 'bananas']), o un objeto Array, por ejemplo, fun.apply(this, new Array('eat', 'bananas')).

Puede también utilizarse arguments como parámetro argsArray. arguments es una variable local a la función. Puede utilizarse para acceder a todos los argumentos no específicados en la llamada al objeto. Por lo tanto, no se requiere conocer todos los argumentos del objeto invocado cuando se utiliza el método apply. Puede utilizarse arguments para pasar los argumentos al objeto invocado. El objeto invocado es entonces responsable por el manejo de los argumentos.

Desde la 5ta edición de ECMAScript se puede utilizar también cualquier tipo de objeto similar a un arreglo, que en términos prácticos significa que tendrá una propiedad length y propiedades integer en el rango (0...length). Por ejemplo, ahora puede utilizarse un NodeList o un objeto personalizado como: {'length': 2, '0': 'eat', '1': 'bananas'}.

Nota: La mayoría de los navegadores, incluidos Chrome 14 e Internet Explorer 9, aún no soportan el uso de objetos similares a un arreglo y arrojarán una excepción.
 

Ejemplos

Utilizando apply para encadenar constructores

Puedes utilizar apply para encadenar constructors para un objeto, similar a Java. En el ejemplo siguiente se crea un método global a Function llamado construct, en cual posibilita el uso de un objeto similar a un arreglo en un constructor en lugar de una lista de argumentos.

Function.prototype.construct = function (aArgs) {
    var fConstructor = this, fNewConstr = function () { fConstructor.apply(this, aArgs); };
    fNewConstr.prototype = fConstructor.prototype;
    return new fNewConstr();
};

Ejemplo de uso:

function MyConstructor () {
    for (var nProp = 0; nProp < arguments.length; nProp++) {
        this["property" + nProp] = arguments[nProp];
    }
}

var myArray = [4, "Hello world!", false];
var myInstance = MyConstructor.construct(myArray);

alert(myInstance.property1); // alerts "Hello world!"
alert(myInstance instanceof MyConstructor); // alerts "true"
alert(myInstance.constructor); // alerts "MyConstructor"
Nota: Este método Function.construct no nativo no funconará con algunos constructores nativos (como Date, por ejemplo). En éstos casos se deberá utilizar el método Function.bind (por ejemplo, supóngase un arreglo como el siguiente para utilizar con el constructor Date: [2012, 11, 4]; en éste caso se tendría que escribir algo como: new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() – de cualquier manera ésta no es la mejor manera de hacerlo y probablemente no debería utilizarse en ningún entorno productivo).

apply y funciones built-in

El uso ingenioso de apply permite utilizar funciones built-in allows you to use built-ins functions for some tasks that otherwise probably would have been written by looping over the array values. As an example here we are going to use Math.max/Math.min to find out the maximum/minimum value in an array.

/* min/max number in an array */
var numbers = [5, 6, 2, 3, 7];

/* using Math.min/Math.max apply */
var max = Math.max.apply(null, numbers); /* This about equal to Math.max(numbers[0], ...) or Math.max(5, 6, ..) */
var min = Math.min.apply(null, numbers);

/* vs. simple loop based algorithm */
max = -Infinity, min = +Infinity;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max)
    max = numbers[i];
  if (numbers[i] < min) 
    min = numbers[i];
}

But beware: in using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. (To illustrate this latter case: if such an engine had a limit of four arguments [actual limits are of course significantly higher], it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.) If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);

Véase también

Etiquetas y colaboradores del documento

Etiquetas: 
Contributors to this page: eespitia.rea, emazarrasa, yakashiro, teoli, chebit, gtoroap
Última actualización por: eespitia.rea,