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 thissłowo kluczowe będzie się odnosić podczas wykonywania funkcji - jeśli jest to obiekt globalny nulllub undefined, do którego windowjest 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 callprzekazania są przekazywane jako argumenty do wywołania funkcji, podczas gdy pojedynczy dodatkowy argument do applyokreś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 baznie zapewnia żadnego kontekstu dla wywołania, więc jest faktycznie takie samo jak baz.call(undefined), więc thiskończy się odwołaniem window. Jeśli chcemy bazwiedzieć, że należy do tej domeny obj, musimy w jakiś sposób podać tę informację, kiedy bazzostanie wywołana, czyli tam, gdzie wchodzi pierwszy argument do calllub applyzamknię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 bindzakresu. 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 bindkończy działanie, funkcja anonimowa nadal ma odniesienie do bindzakresu, więc bindzakres 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ą thisbę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); }};