Wywołania funkcji
Funkcje są tylko rodzajem obiektu.
Wszystkie obiekty Function mają metody wywołania i zastosowania , które wykonują wywołany obiekt Function.
Po wywołaniu pierwszy argument tych metod określa obiekt, do którego this
słowo kluczowe będzie się odnosić podczas wykonywania funkcji - jeśli jest to obiekt globalny null
lub undefined
, do którego window
jest on używany this
.
Wywołanie funkcji ...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
... z nawiasami - foo()
- jest równoważne foo.call(undefined)
lub foo.apply(undefined)
, co jest faktycznie takie samo jak foo.call(window)
lub foo.apply(window)
.
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Dodatkowe argumenty do call
przekazania są przekazywane jako argumenty do wywołania funkcji, podczas gdy pojedynczy dodatkowy argument do apply
określenia argumentów dla wywołania funkcji jako obiekt podobny do tablicy.
Zatem foo(1, 2, 3)
jest równoważne z foo.call(null, 1, 2, 3)
lub foo.apply(null, [1, 2, 3])
.
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
Jeśli funkcja jest własnością obiektu ...
var obj =
{
whereAmI: "obj",
foo: foo
};
... dostęp do odwołania do funkcji za pośrednictwem obiektu i wywołanie go w nawiasach - obj.foo()
- jest równoważne z foo.call(obj)
lub foo.apply(obj)
.
Jednak funkcje utrzymywane jako właściwości obiektów nie są „powiązane” z tymi obiektami. Jak widać w powyższej definicji obj
, ponieważ Funkcje są tylko rodzajem Object, można się do nich odwoływać (a zatem mogą być przekazywane przez odwołanie do wywołania funkcji lub zwracane przez odwołanie z wywołania funkcji). Gdy odwołanie do funkcji jest przekazywana bez dodatkowych informacji o tym, gdzie został przekazany od przeprowadza z nim, dlatego dodaje się dzieje:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
Wywołanie naszego odwołania do funkcji baz
nie zapewnia żadnego kontekstu dla wywołania, więc jest faktycznie takie samo jak baz.call(undefined)
, więc this
kończy się odwołaniem window
. Jeśli chcemy baz
wiedzieć, że należy do tej domeny obj
, musimy w jakiś sposób podać tę informację, kiedy baz
zostanie wywołana, czyli tam, gdzie wchodzi pierwszy argument do call
lub apply
zamknięcie.
Łańcuchy zakresowe
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
Kiedy funkcja jest wykonywana, tworzy nowy zakres i ma odniesienie do dowolnego zakresu obejmującego. Gdy funkcja anonimowa jest tworzona w powyższym przykładzie, ma odniesienie do zakresu, w którym została utworzona, czyli bind
zakresu. Jest to znane jako „zamknięcie”.
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
Kiedy próbujesz uzyskać dostęp do zmiennej, ten „łańcuch zasięgu” idzie do znalezienia zmiennej o podanej nazwie - jeśli bieżący zakres nie zawiera zmiennej, patrzysz na następny zakres w łańcuchu i tak dalej, aż dojdziesz zasięg globalny. Kiedy funkcja anonimowa jest zwracana i bind
kończy działanie, funkcja anonimowa nadal ma odniesienie do bind
zakresu, więc bind
zakres nie „znika”.
Biorąc pod uwagę wszystkie powyższe, powinieneś być teraz w stanie zrozumieć, jak działa zakres w poniższym przykładzie i dlaczego technika przekazywania funkcji wokół „wstępnie powiązanej” z określoną wartością this
będzie miała, gdy zostanie nazwana:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};