Недавно один из моих друзей спросил меня о выходе следующего кода
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);Недавно один из моих друзей спросил меня о выходе следующего кода
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1); Разница заключается в том, что this контекст каждого вызова метода.
В первом случае, поскольку вызов является просто fn(); , this контекст - Window. Длина var length = 10; объявление переменной наверху происходит в контексте root/Window, поэтому window.length должно быть 10, следовательно, 10 в консоли от первого вызова функции.
Поскольку arguments не являются массивом, но на самом деле являются объектом типа Arguments, вызывающие arguments[0]() означает, что this контекст вызова функции будет из родительского объекта, поэтому this.length эквивалентен arguments.length, следовательно 2 (поскольку есть 2 аргумента). (См. @Travis J для более подробного объяснения этой части.)
Если бы вы добавили
this.fn = fn;
this.fn();
к функции method() результат будет равен 5.
Это связано с тем, как this работает в различных областях, на которые оно ссылается.
Обратите внимание на выходы this.toString() и вы увидите, на что ссылается цель.
Начиная с вызова функции f непосредственно из окна, this будет ссылаться на Window и поэтому длина будет Window.length которая была объявлена равной 10.
Переходим к, если мы назначим f непосредственно как метод obj, тогда this будет ссылаться на obj и, следовательно, длина будет obj.length которая была объявлена равной 5.
Там, где это становится интересным/запутанным, вы передаете f в качестве параметра для использования method obj.
ПРИМЕЧАНИЕ. Результат здесь будет специфичным для браузера. Запустите его в Safari и Chrome и обратите внимание на разные выходы.
В обоих браузерах arguments[0]() псевдо эквивалентны arguments.0() (хотя и не разрешены синтаксически для arguments), что является точно таким же поведением, которое наблюдалось ранее с obj.fn() что означает, что arguments являются эталонной целью. Который, как заметил, - количество аргументов, переданных obj.method.
Выполнение fn внутри method - это функция обратного вызова, для которой вы можете найти более обширный ответ здесь.
var length = 10;
function f() {
console.log(this.toString());
console.log(this.length);
}
var obj = {
length: 5,
fn: f,
method: function(fn) {
fn();
arguments[0]();
}
};
f()
f(1);
obj.fn();
obj.fn(1);
obj.method(f, 1);
obj.method(f, 1, 2); @musicnothing является полностью правильным, this привязка отличается между двумя различными вызовами fn.
Тем не менее, до сих пор, кажется, некоторая путаница в рассуждения, почему arguments теперь this цель, которую я обращусь.
this привязки MDN хранятся внутри Execution Contexts ECMA, которые по существу управляют областью в JavaScript.
Когда вызывается функция, создается объект arguments. Объект arguments имеет свой собственный контекст выполнения, что означает, что он имеет свою привязку, собственную переменную среду и собственную лексическую среду. Когда построено, то arguments объект значения сохраняются в переменной среде, что делают любые ссылки из этой точки по отношению к arguments объекта контекста исполнения.
По дизайну объект arguments является подобным массиву, что в основном означает, что он согласен иметь свойство length и более неопределенно, что доступ к индексу, который меньше свойства length, должен иметь значение. В результате вы можете получить доступ к своим ссылкам с индексами через фасад, однако важно иметь в виду, где они находятся в этом месте.
Ответ равен 10, 2 из-за разных значений "this".