Вызовы функций
Функции - это просто тип объекта.
Все объекты 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); }};