Знайте выражение JavaScript Function Expression vs Function Declaration, но что это? Именованное выражение функции?
Возможный дубликат:
JavaScript: var functionName = function() {} vs function functionName() {}
В чем отличие выражения функции от объявления в Javascript?
Я знаю различия между декларациями функций и выражениями, но столкнулся с этим кодом с использованием имени функции и хочу понять, что происходит, когда мы запускаем его:
var abc = function def() {
console.log("Wait! What??");
}
Я знаю, что это не способ JavaScript, но просто хочу знать несколько вещей:
- Что происходит с
abc
? Почему это работает? abc
можно вызвать, но не def
, почему?
- Является ли это объявлением функции или выражением?
-
def
undefined
- почему? Если это так,
утечки памяти?
- Почему
abc.prototype
есть функция def
?
Спасибо
Ответы
Ответ 1
Что происходит с abc?
Он содержит объект функции. Если вы ничего не делаете с этим, это будет сбор мусора.
Почему это работает?
Почему бы и нет? Что "работает"?
abc может быть вызван, но не def, почему?
Это справедливо только извне, а не в IE. См. Ниже.
Является ли это объявлением функции или выражением?
Это выражение функции. Вы можете легко увидеть, что, поскольку это часть выражения присваивания; декларации всегда должны быть на верхнем уровне (функций или глобального кода)
def undefined - почему?
Только со стороны. Выражение функции не создает переменные. "def" - это name функции, а внутри функции она также является ссылкой на функцию. Это позволяет рекурсию, например, без использования каких-либо внешних переменных.
var abc = function def() {
def === abc; // true
def.name; // "def"
}
abc();
def; // undefined
Если это предполагается, есть ли утечки памяти?
Да, в Internet Explorer. Он создает две различные функции из этого кода. Подробнее см. http://kangax.github.com/nfe/#jscript-bugs
Почему abc.prototype является функцией def?
Это не так. Это просто объект. Возможно, это показано с этим именем в вашей консоли, так как оно относится к функции с именем "def".
Ответ 2
Это названная функция expressio. Возможное использование для этого может быть:
var abc = function def() {
def.test = 'Wait!'; //< sort of a static property
console.log(def.test+" What??");
}
Но остерегайтесь.
Ответ 3
Это Выражение функции 2
Выражения функции могут также иметь имена; имена выражений функций находятся только в области действия в теле функции 1. (Поскольку ECMAScript 5th edition обесценивает arguments.callee
, это единственный простой способ записи рекурсивной "анонимной" функции.)
Поскольку это выражение функции, имя не может 1 вводить новое связывание во внешней области.
Кроме того, все функции являются объектами в JavaScript. В f(..)
, f
оценивается до того, как он "вызывается" с помощью (..)
; если f
не оценил функцию, тогда возникает ошибка. Вот почему обратные вызовы, которые являются просто функциями, могут быть названы переменными и переданы как параметры.
Кроме того, проверьте предположение/утверждение о прототипе:
var abc = function def() {}
abc.prototype === abc // -> false
abc.name // -> "def"
1 См. ответ Берги.
2 Как легко сказать, что это?
Правила грамматики позволяют анализировать только function ..
как декларацию функции, если она является SourceElement, хотя большинство движков все еще [неправильно] проанализируйте объявление функции как Statement. Произведения SourceElement выполняются только на "блоке" верхнего уровня программы или на "блоке" верхнего уровня для функции.
В любом случае, когда есть function ..
, который появляется в месте, которое требует Expression, оно будет анализироваться как функция Expression. Примеры, которые все анализируются как выражения функций:
// Can only assign values: Statements do not have values!
var f = function () {}
var g = function gName () {} // see Bergi answer
// Can only pass values: Statements do not have values!
doIt(function () {}) // callback / "anonymous function"
// IIFE: Immediately-Invoked Function Expression
;(function () {})() // standard IIFE
;(function () {} ()) // alternative standard IIFE
;+function () {} () // curious way to write an IIFE
// basically you can use any unary operator to turn it into an expression not only
// + but also - ! ~ and so on which will modify the return value accordingly
Дело в том, что в каждом из приведенных выше случаев function ..
появляется в месте грамматики, требующем выражения и, таким образом, анализируется как выражение функции. (Точки с запятой в начале строк выше избегают "двусмысленности" с ASI, что требуется при написании в стиле без запятой, как я предпочитаю.)
Однако. ;function () {} ()
и ;function f () {} ()
являются недопустимым синтаксисом - почему?; -)
Ответ 4
Это именованное функциональное выражение.
В отличие от деклараций функций Идентификатор выражения функции не является обязательным.
Ваша функция def
не вызывается сразу - вся функция передается в abc
и должна быть явно вызвана abc()
.
§13 спецификации ES5 указывает, как создаются именованные функциональные выражения. Прочтите третье производственное правило о том, как создаются именованные функциональные выражения.
ПРИМЕЧАНИЕ. Идентификатор в выражении Function можно ссылаться из внутри функции FunctionExpression FunctionBody, чтобы функция называть себя рекурсивно. Однако, в отличие от FunctionDeclaration, Идентификатор в выражении Function не может ссылаться и не влияет на область применения Expression.
Все последние браузеры обрабатывают это правильно, поэтому вам не нужно беспокоиться об утечке памяти или других странных вещах (некорректная обработка выполняется только в старом IE <= 8).
Ответ 5
Ваш пример - это выражение с именем (named).
Разница между ними заключается в том, как браузер загружает их.
Объявления функций загружаются до, любой код выполняется.
Выражения функции загружаются только , когда интерпретатор достигает этой строки кода.
Это означает:
abc();
var abc = function() {
console.log("Wait! What??");
}
Не работает, но:
def();
function def() {
console.log("Wait! What??");
}
Will.
Теперь в вашем примере вы можете получить доступ к def
, но только внутри самой функции.
var abc = function def() {
console.log(def);
}
abc();
// Logs:
//function def() {
// console.log(def);
//}