Następuje fragment z Closure: The Definitive Guide autorstwa Michaela Bolina . Może wydawać się nieco długi, ale jest nasycony dużą ilością wglądu. Z „Dodatku B. Często źle rozumiane pojęcia JavaScript”:
Co this
dotyczy wywołania funkcji
Podczas wywoływania funkcji formularza foo.bar.baz()
obiekt foo.bar
nazywany jest odbiorcą. Gdy funkcja jest wywoływana, odbiornik jest używany jako wartość dla 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);
Jeśli po wywołaniu funkcji nie ma jawnego odbiornika, wówczas obiekt globalny staje się odbiorcą. Jak wyjaśniono w „goog.global” na stronie 47, okno jest obiektem globalnym, gdy JavaScript jest uruchamiany w przeglądarce internetowej. Prowadzi to do zaskakujących zachowań:
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
Chociaż obj.addValues
i f
odnoszą się do tej samej funkcji, zachowują się inaczej, gdy nazywa ponieważ wartość odbiornika jest inna w każdej rozmowie. Z tego powodu przy wywoływaniu funkcji, do której się this
ona odnosi , ważne jest, aby upewnić się, że this
będzie miała poprawną wartość, gdy zostanie wywołana. Dla jasności, gdyby this
nie odwoływać się do treści funkcji, zachowanie f(20)
i obj.addValues(20)
byłoby takie samo.
Ponieważ funkcje są pierwszorzędnymi obiektami w JavaScript, mogą mieć własne metody. Wszystkie funkcje mają metody call()
i apply()
które pozwalają na ponowne zdefiniowanie odbiornik (czyli obiekt, który this
odnosi się do) przy wywołaniu funkcji. Podpisy metod są następujące:
/**
* @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;
Zauważ, że jedyna różnica między call()
i apply()
polega na tym, że call()
odbiera parametry funkcji jako poszczególne argumenty, podczas gdy apply()
odbiera je jako pojedynczą tablicę:
// 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]);
Następujące wywołania są równoważne f
i obj.addValues
odnoszą się do tej samej funkcji:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
Ponieważ jednak ani call()
nie apply()
używa wartości własnego odbiornika do zastąpienia argumentu odbiorcy, gdy nie jest on określony, następujące działania nie będą działać:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
Wartość this
nigdy nie może być null
lub undefined
gdy funkcja jest wywoływana. Gdy null
lub undefined
jest dostarczane jako odbiornik do call()
lub apply()
, zamiast tego używany jest obiekt globalny jako wartość dla odbiornika. Dlatego poprzedni kod ma ten sam niepożądany efekt uboczny dodawania właściwości o nazwie value
do obiektu globalnego.
Pomocne może być myślenie o funkcji jako nie posiadającej wiedzy o zmiennej, do której jest przypisana. Pomaga to wzmocnić ideę, że wartość tego będzie ograniczona, gdy funkcja zostanie wywołana, a nie kiedy zostanie zdefiniowana.
Koniec wyciągu.
a
w przypadku ubiegania się o tablicę argów ic
wzywając do kolumn arg.