Почему мои имена функций JavaScript сталкиваются?
Я написал следующий script, чтобы увидеть, что происходит, когда переменная и функция, у которой есть назначенная ей функция, имеют свои имена:
var f = function() {
console.log("Me original.");
}
function f() {
console.log("Me duplicate.");
}
f();
Выход, который я получаю, - "Я оригинален". Почему другая функция не вызывалась?
Кроме того, если я изменю свое первоначальное назначение на var f = new function() {
, я получу "Я оригинал", а затем произнесет TypeError object is not a function
. Может кто-нибудь объяснить?
Ответы
Ответ 1
Объявления функций поднимаются (перемещаются вверху) в JavaScript. Хотя это неверно с точки зрения порядка синтаксического анализа, код, который у вас есть, семантически такой же, как и после объявления функций:
function f() {
console.log("Me duplicate.");
}
var f = function() {
console.log("Me original.");
}
f();
Что, в свою очередь, за исключением имени функции, совпадает с:
var f = function() {
console.log("Me duplicate.");
}
var f = function() {
console.log("Me original.");
}
f();
Это, в свою очередь, из-за переменного подъема - это то же самое, что:
var f;
f = function() {
console.log("Me duplicate.");
}
f = function() {
console.log("Me original.");
}
f();
Что объясняет, что вы получаете, вы переопределяете функцию. В более общем плане в JavaScript допускаются множественные объявления var
- var x = 3; var x = 5
является совершенно законным. В новом стандарте ECMAScript 6 инструкции let
запрещают это.
Эта статья от @kangax делает фантастическую работу по демистификации функций в javascript
Ответ 2
Если не похоже, что кто-то ответил на ваш последующий вопрос, поэтому я отвечу на него здесь, хотя обычно вы должны задавать дополнительные вопросы в виде отдельных вопросов.
Вы спросили, почему это:
var f = new function() {
console.log("Me original.");
}
function f() {
console.log("Me duplicate.");
}
f();
выводит "Я оригинал". и затем ошибка.
Что здесь происходит, так это то, что new
заставляет эту функцию использовать в качестве конструктора. Таким образом, это эквивалентно следующему:
function myConstructor() {
console.log("Me original.");
}
var f = new myConstructor();
function f() {
console.log("Me duplicate.");
}
f();
И благодаря функции подъема, которую объяснил Бенджамин, приведенное выше по существу эквивалентно этому:
var myConstructor = function() {
console.log("Me original.");
};
var f = function() {
console.log("Me duplicate.");
};
f = new myConstructor();
f();
Это выражение:
var f = new function() {
console.log("Me original.");
}
вызывает создание и назначение нового объекта f
, используя анонимную функцию в качестве конструктора. "Я оригинал". печатается по мере выполнения конструктором. Но построенный объект не является самой функцией, поэтому, когда это в конечном итоге выполняется:
f();
вы получите сообщение об ошибке, потому что f
не является функцией.
Ответ 3
Простите меня, если это неправильный подход к добавлению точки. Я не был здесь очень много, и я бы приветствовал конструктивное руководство и/или критику.
Бенджамин отвечает на вопрос OP превосходно, но я хотел бы добавить одну настройку, которая даст нам полный обзор подъема и его странностей.
Если мы начнем исходный код с вызова f
, вот так:
f();
var f = function() {
console.log("Me original.");
};
function f() {
console.log("Me duplicate.");
}
f();
Выход будет следующим:
Me duplicate.
Me original.
Причина заключается в том, что инструкции var
и function
поднимаются несколько разными способами.
В var
объявление перемещается в верхнюю часть текущей области *, но любое присваивание не поднимается. Что касается значения объявленного var, то оно undefined, пока не будет достигнута исходная строка контировки.
В выражениях function
как декларация, так и определение поднимаются. Выражения функции, используемые в конструкции var f = function() {...
, не поднимаются.
Итак, после подъема выполнение выполняется так, как если бы код был:
var f; // declares var f, but does not assign it.
// name and define function f, shadowing the variable
function f() {
console.log("Me duplicate.");
}
// call the currently defined function f
f();
// assigns the result of a function expression to the var f,
// which shadows the hoisted function definition once past this point lexically
f = function() {
console.log("Me original.");
}
// calls the function referenced by the var f
f();
* Вся область JavaScript является лексической или функциональной, областью видимости, но казалось, что это просто путают вещи, чтобы использовать слово f в этой точке.