Function.prototype.apply()

Deze vertaling is niet volledig. Help dit artikel te vertalen vanuit het Engels.

De apply() methode roept een functie aan met een gegeven this waarde en argumenten gedefineerd als een array (of een array-achtig object).

Let op: Hoewel de syntax van deze functie vrijwel gelijk is aan die van call(), is het fundamentele verschill met call() dat deze een lijst van argumenten accepteerd, twerijl apply() een enkele array van argumenten verwacht.

Syntax

fun.apply(thisArg, [argsArray])

Parameters

thisArg
De waarde van this die aan de call voor fun wordt meegegeven. Hou er rekening mee dat dit mogelijk niet de waarde is die de methode ziet: Als de methode gedefineerd is in non-strict mode code, dan zullen null en undefined worden vervangen met het globale object en primitieve waardes worden omgezet naar objecten (boxed).
argsArray
Een array-achtig object met de argumenten waarmee fun moet worden aangeroepen, of null of undefined als er geen argumenten worden gegeven. Vanaf ECMAScript 5  kunnen deze argumenten een generieke array-achtig object zijn in plaats van een array. Hieronder meer informatie over browser compatibiliteit.

Return waarde

Het resultaat van de aanroep met de gegeven this waarde en argumenten.

Omschrijving

Het is mogelijk om een ander this object toe te wijzen indien je een bestaande functie aanroept. this verwijst naar het huidige object, het object wat de aanroep doet. Met apply kun je een methode eenmaal schrijven en dan door overerving gebruiken in een ander object, zonder dat je de methode hoeft te herschrijven voor het nieuwe object.

Apply heeft veel overeenkomsten met call() maar heeft voor argumenten een andere notatie. je kunt een array van argumenten meegeven in plaats van een benoemde set aan argumenten. Met apply kun je zowel een array literal (bijv. fun.apply(this, ['eat', 'bananas'])) gebruiken als een Array object (bijv. fun.apply(this, new Array('eat', 'bananas'))).

Je kunt ook arguments meegeven als argsArray parameter. arguments is een locale variabele of functie, en kan gebruikt worden voor alle ongespecificeerde argumenten voor het aan te roepen object. Dit houd in dat je niet precies hoeft te weten welke argumenten nodig zijn voor het aan te roepen object als je apply() gebruikt. Het aan te roepen object is vervolgens verantwoordleijke voor de afhandeling van de argumenten.

Vanaf de 5e editie van ECMAScript kun je ook een willekeurig array-achtig object gebruiken, wat inhoud dat het een length en getallen (met bereik 0 ... length-1) als properties heeft. Je kunt bijvoorbeeld een NodeList of een op maat gemaakt object (zoals: { 'length': 2, '0': 'eat', '1': 'bananas' }) gebruiken.

Let op: De meeste browsers, waaronder Chrome 14 en Internet Explorer 9, ondersteunen array-achtige objecten nog niet. Deze zullen een exceptie geven als je het toch probeert.

Voorbeelden

Apply gebruiken om constructors te ketenen

Apply kan gebruikt worden om constructorsvoor een object aan elkaar te ketenen, gelijk aan de werkwijze in java. In het volgende voorbeeld maken we een globale Function  methode genaamd construct, welke je in staat stelt om een array-achtig object te gebruiken in plaats van een lijst van argumenten.

Function.prototype.construct = function (aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

Let op: De Object.create() methode die hierboven gebruikt wordt is vrij nieuw. Voor een alternatieve methode die gebruik maakt van closures kun je onderstaande voorbeeld ook gebruiken:

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

Voorbeeld gebruik:

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

console.log(myInstance.property1);                // logs 'Hello world!'
console.log(myInstance instanceof MyConstructor); // logs 'true'
console.log(myInstance.constructor);              // logs 'MyConstructor'

Let op: Deze niet native Function.construct methode zal niet werken met sommige native constructors  (zoals Date, bij voorbeeld). In deze gevallen gebruik je de Function.prototype.bind methode (bij voorbeeld, stel je een array als de volgende voor, te gebruiken met Date constructor: [2012, 11, 4]; in dit geval schrijf je bijvoorbeeld: new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() — Hoewel dit werkt is dit in meerdere opzichten een kwetsbare manier die niet in productie gebruikt zou moeten worden).

Gebruik van apply en ingebouwde functies

Slim gebruik van apply geeft de mogelijkheid om standaard javascript functies te gebruiken voor handelingen die anders in een loop zouden gebeuren. Als voorbeeld gaan we Math.max/Math.min gebruiken wat de maximum en minimum waardes zijn in een 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];
  }
}

Maar pas op: door apply op deze manier te gebruiken loop je het risico over de maximum argument limiet van JavaScript's engine heen te gaan. De consequenties van het gebruik van apply op een functie met te veel argumenten (denk aan meer dan tienduizen argumenten) varieren tussen de verschillende engines (JavaScriptCore heeft een hard-coded  argument limiet van 65536), omdat de limiet (en het gedrag bij extreem grote hoeveelheden objecten) niet is opgenomen in een standaard. Sommige engines zullen een exceptie opgooien, anderen kunnen mogelijk zelfs het aantal argumenten afkappen bij het maximum. Als je array toch het risico loopt te groeien voorbij de limiet, kun je beter een hybriede implementatie maken: voer je functie uit over stukken van een array, bijvoorbeeld: 

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

Gebruik van apply bij "monkey-patching"

Apply kan enorm nuttig zijn bij het monkey-patchen van browser-eigen-  of framework-functies. Met bijvoorbeeld de someobject.foo functie, kun je de functie aanpassen op de volgende, ietwat smerige manier:

var originalfoo = someobject.foo;
someobject.foo = function() {
  // Do stuff before calling function
  console.log(arguments);
  // Call the function as it would have been called normally:
  originalfoo.apply(this, arguments);
  // Run stuff after, here.
}

Specificaties

Specification Status Comment
ECMAScript 3rd Edition (ECMA-262) Standard Initiele definitie. Geimplementeerd in JavaScript 1.3.
ECMAScript 5.1 (ECMA-262)
The definition of 'Function.prototype.apply' in that specification.
Standard  
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Function.prototype.apply' in that specification.
Standard  
ECMAScript 2017 Draft (ECMA-262)
The definition of 'Function.prototype.apply' in that specification.
Draft  

Browser compatibiliteit

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (Yes) (Yes) (Yes) (Yes) (Yes)
ES 5.1 generic array-like object as arguments (Yes) 4.0 (2.0) ? ? ?
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support (Yes) (Yes) (Yes) (Yes) (Yes) (Yes)
ES 5.1 generic array-like object as arguments ? ? 4.0 (2.0) ? ? ?

See also

Documentlabels en -medewerkers

 Aan deze pagina hebben bijgedragen: SenorSpiekbrief
 Laatst bijgewerkt door: SenorSpiekbrief,