Вызовы функций
Функции - это просто тип объекта.
Все объекты Function имеют методы вызова и применения, которые выполняют объект Function, к которому они обращаются .
При вызове первый аргумент этих методов указывает объект, на который будет ссылаться thisключевое слово во время выполнения функции - если это nullили undefinedглобальный объект window, для которого используется this.
Таким образом, вызов функции ...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
... с круглыми скобками - foo()- эквивалентно foo.call(undefined)или foo.apply(undefined), что фактически совпадает с foo.call(window)или foo.apply(window).
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Дополнительные аргументы to callпередаются как аргументы для вызова функции, тогда как один дополнительный аргумент to applyможет указывать аргументы для вызова функции как объект, подобный массиву.
Таким образом, foo(1, 2, 3)эквивалентно foo.call(null, 1, 2, 3)или 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"
Если функция является свойством объекта ...
var obj =
{
whereAmI: "obj",
foo: foo
};
... получить доступ к ссылке на функцию через объект и вызвать ее в скобках - obj.foo()- эквивалентно foo.call(obj)или foo.apply(obj).
Однако функции, содержащиеся в свойствах объектов, не «привязаны» к этим объектам. Как видно из objприведенного выше определения , поскольку функции являются просто типом объекта, на них можно ссылаться (и, таким образом, их можно передавать по ссылке на вызов функции или возвращать по ссылке из вызова функции). Когда ссылка на функции передается никакой дополнительной информации о том, где он был принят с осуществляется с ней, поэтому следующее не происходит:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
Вызов нашей ссылки на функцию, bazне предоставляет никакого контекста для вызова, поэтому он фактически такой же, как и baz.call(undefined), в thisконечном итоге, ссылается window. Если мы хотим bazзнать, к чему он принадлежит obj, нам нужно каким-то образом предоставить эту информацию при bazвызове, где вступают в действие первый аргумент callили applyи замыкания.
Цепи прицела
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
Когда функция выполняется, она создает новую область и имеет ссылку на любую вмещающую область. Когда анонимная функция создается в приведенном выше примере, она имеет ссылку на область, в которой она была создана, что является bindобластью действия. Это известно как «закрытие».
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
Когда вы пытаетесь получить доступ к переменной, эта «цепочка областей действия» обходит переменную с заданным именем - если текущая область не содержит переменную, вы просматриваете следующую область в цепочке и так далее, пока не достигнете глобальный охват. Когда анонимная функция возвращается и bindзавершает выполнение, анонимная функция все еще имеет ссылку на bindобласть действия, поэтому bindобласть действия не «исчезает».
Учитывая все вышесказанное, вы должны теперь иметь возможность понять, как работает область действия в следующем примере, и почему будет работать метод для передачи функции вокруг «pre-bound» с определенным значением this, когда она вызывается:
>>> 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); }};