Функциональные вызовы
Функции - это просто тип объекта.
Все объекты Function имеют call и apply методы, которые выполняют объект 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"
Дополнительные аргументы для call
передаются в качестве аргументов для вызова функции, тогда как один дополнительный аргумент для 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
не "уходит".
Учитывая все вышеизложенное, вы должны теперь иметь возможность понять, как работает область действия в следующем примере, и почему методика передачи функции вокруг «предопределенной» с определенным значением this
будет иметься, когда она названные работы:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"