Недавно я начал поддерживать чужой код JavaScript. Я исправляю ошибки, добавляю функции, а также пытаюсь привести код в порядок и сделать его более согласованным.
Предыдущий разработчик использовал два способа объявления функций, и я не могу понять, есть ли причина этого или нет.
Два способа:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Каковы причины использования этих двух разных методов и каковы плюсы и минусы каждого? Есть ли что-нибудь, что можно сделать одним методом, но нельзя сделать другим?
javascript
function
syntax
idioms
Ричард Гарсайд
источник
источник
var a = 1; var b = 2;
становитсяvar a; var b; a = 1; b = 2
. Поэтому, когда вы объявляете functionOne, он объявляется, но его значение не устанавливается сразу. Принимая во внимание, что так как functionTwo является просто объявлением, он помещается в верхнюю часть области видимости. # 2 functionTwo позволяет получить доступ к свойству name, что очень помогает при попытке отладки чего-либо.function f(){}
противvar f = function(){};
.Ответы:
Разница в том, что
functionOne
это выражение функции, и поэтому оно определяется только при достижении этой строки, тогда какfunctionTwo
является объявлением функции и определяется, как только его окружающая функция или скрипт выполняется (из-за подъема ).Например, выражение функции:
И объявление функции:
Исторически объявления функций, определенные в блоках, обрабатывались непоследовательно между браузерами. Строгий режим (введенный в ES5) решил эту проблему путем определения объёмов функций в их включающем блоке.
источник
functionOne
просто переменная, которой назначена анонимная функция, тогда какfunctionTwo
на самом деле это именованная функция. Позвоните.toString()
обоим, чтобы увидеть разницу. Это важно в некоторых случаях, когда вы хотите получить название функции программно.function expression
второйfunction declaration
. Вы можете прочитать больше на эту тему здесь: javascriptweblog.wordpress.com/2010/07/06/…Во-первых, я хочу исправить Грега:
function abc(){}
это также ограничено - имяabc
определено в области, где встречается это определение. Пример:Во-вторых, можно сочетать оба стиля:
xyz
будет определен как обычно,abc
не определен во всех браузерах, кроме Internet Explorer - не полагайтесь на его определение. Но это будет определено внутри его тела:Если вы хотите использовать псевдонимы для всех браузеров, используйте этот вид объявления:
В этом случае оба
xyz
иabc
являются псевдонимами одного и того же объекта:Одной из веских причин для использования комбинированного стиля является атрибут «имя» функциональных объектов ( не поддерживается Internet Explorer ). В основном, когда вы определяете функцию, как
его имя присваивается автоматически. Но когда вы определяете это как
его имя пустое - мы создали анонимную функцию и присвоили ее некоторой переменной.
Еще одна веская причина для использования комбинированного стиля - использовать короткое внутреннее имя для ссылки на себя, предоставляя длинное не конфликтующее имя для внешних пользователей:
В приведенном выше примере мы можем сделать то же самое с внешним именем, но оно будет слишком громоздким (и медленным).
(Другой способ сослаться на себя - использовать
arguments.callee
, который все еще относительно длинный и не поддерживается в строгом режиме.)В глубине души JavaScript обрабатывает оба утверждения по-разному. Это объявление функции:
abc
здесь определяется везде в текущей области:Кроме того, он поднял через
return
заявление:Это функциональное выражение:
xyz
здесь определяется с точки назначения:Объявление функции в сравнении с выражением функции является реальной причиной, по которой Грег демонстрирует разницу.
Интересный факт:
Лично я предпочитаю объявление «выражение функции», потому что таким образом я могу контролировать видимость. Когда я определяю функцию как
Я знаю, что я определил функцию локально. Когда я определяю функцию как
Я знаю, что я определил это глобально, при условии, что я не определил
abc
нигде в цепочке областей. Этот стиль определения устойчив, даже когда используется внутриeval()
. Хотя определениезависит от контекста и может заставить вас угадать, где он определен, особенно в случае
eval()
- ответ таков: это зависит от браузера.источник
var abc = function(){}; console.log(abc.name);
больше не производит""
, а"abc"
вместо этого.Вот краткое изложение стандартных форм, которые создают функции: (Первоначально написано для другого вопроса, но адаптировано после перемещения в канонический вопрос.)
Сроки:
Быстрый список:
Объявление функции
«Анонимное»
function
выражение (которое, несмотря на термин, иногда создает функции с именами)Именованное
function
выражениеИнициализатор функций доступа (ES5 +)
Выражение функции стрелки (ES2015 +) (которое, как и выражения анонимной функции, не содержит явного имени и все же может создавать функции с именами)
Объявление метода в инициализаторе объекта (ES2015 +)
Объявления конструктора и метода в
class
(ES2015 +)Объявление функции
Первая форма - это объявление функции , которое выглядит так:
Объявление функции - это объявление ; это не утверждение или выражение. Таким образом, вы не следуете за ним
;
(хотя это безвредно).Объявление функции обрабатывается, когда выполнение входит в контекст, в котором оно появляется, перед выполнением любого пошагового кода. Создаваемой ей функции присваивается собственное имя (
x
в примере выше), и это имя помещается в область, в которой появляется объявление.Поскольку он обрабатывается перед любым пошаговым кодом в том же контексте, вы можете сделать что-то вроде этого:
До ES2015, спецификация не не охватывает то , что двигатель JavaScript должен делать , если поместить объявление функции внутри структуры управления , как
try
,if
,switch
,while
и т.д., как это:А поскольку они обрабатываются до запуска пошагового кода, сложно знать, что делать, когда они находятся в структуре управления.
Хотя это не было указано до ES2015, это было допустимое расширение для поддержки объявлений функций в блоках. К сожалению (и неизбежно), разные двигатели делали разные вещи.
Начиная с ES2015, в спецификации сказано, что делать. Фактически, это дает три отдельных действия:
Правила для свободных режимов хитры, но в строгом режиме объявления функций в блоках просты: они локальны для блока (они имеют область видимости блока , которая также является новой в ES2015), и они поднимаются наверх блока. Так:
«Анонимное»
function
выражениеВторая распространенная форма называется выражением анонимной функции :
Как и все выражения, оно оценивается, когда достигается при пошаговом выполнении кода.
В ES5 созданная функция не имеет имени (она анонимна). В ES2015, функции по возможности присваивается имя, выводя его из контекста. В приведенном выше примере имя будет
y
. Нечто подобное происходит, когда функция является значением инициализатора свойства. (Подробную информацию о том, когда это происходит и правилах, ищитеSetFunctionName
в спецификации - она появляется повсюду .)Именованное
function
выражениеТретья форма - это выражение с именованной функцией («NFE»):
Функция, которую она создает, имеет собственное имя (
w
в данном случае). Как и все выражения, это оценивается, когда оно достигается при пошаговом выполнении кода. Имя функции не добавляется в область, в которой появляется выражение; имя находится в области действия самой функции:Обратите внимание, что NFE часто являются источником ошибок для реализаций JavaScript. Например, IE8 и более ранние версии обрабатывают NFE совершенно неправильно , создавая две разные функции в два разных момента времени. Ранние версии Safari также имели проблемы. Хорошей новостью является то, что в текущих версиях браузеров (IE9 и выше, текущий Safari) таких проблем больше нет. (Но на момент написания этой статьи, к сожалению, IE8 все еще широко используется, и поэтому использование NFE с кодом для Интернета в целом все еще проблематично.)
Инициализатор функций доступа (ES5 +)
Иногда функции могут проникнуть в значительной степени незамеченными; это в случае с функциями доступа . Вот пример:
Обратите внимание, что когда я использовал функцию, я не использовал
()
! Это потому, что это функция доступа для свойства. Мы получаем и устанавливаем свойство обычным способом, но за кулисами вызывается функция.Вы также можете создавать функции доступа с помощью
Object.defineProperty
,Object.defineProperties
и менее известный второй аргумент дляObject.create
.Выражение функции стрелки (ES2015 +)
ES2015 приносит нам функцию стрелки . Вот один пример:
Видишь эту
n => n * 2
вещь, скрывающуюся вmap()
звонке? Это функция.Несколько вещей о функциях стрелок:
У них нет своего
this
. Вместо этого, они близко надthis
из контекста , в котором они определены. (Они также закрываютсяarguments
и, где это уместноsuper
.) Это означает, чтоthis
внутри них то же самое, что и то,this
где они созданы, и их нельзя изменить.Как вы уже заметили, вы не используете ключевое слово
function
; вместо этого вы используете=>
.Приведенный
n => n * 2
выше пример является одной из них. Если у вас есть несколько аргументов для передачи функции, вы используете parens:(Помните, что
Array#map
запись передается как первый аргумент, а индекс как второй.)В обоих случаях тело функции является просто выражением; возвращаемое значение функции будет автоматически результатом этого выражения (вы не используете явное
return
).Если вы делаете больше, чем просто одно выражение, используйте
{}
и явноеreturn
(если вам нужно вернуть значение), как обычно:Версия без
{ ... }
называется функцией стрелки с телом выражения или кратким телом . (Также: краткая функция стрелки.) Функция с{ ... }
определением тела - это функция стрелки с телом функции . (Также: функция многословной стрелки.)Объявление метода в инициализаторе объекта (ES2015 +)
ES2015 допускает более короткую форму объявления свойства, которое ссылается на функцию, называемую определением метода ; это выглядит так:
почти эквивалент в ES5 и более ранних версиях:
Разница (кроме многословия) в том, что метод может использовать
super
, а функция - нет. Так, например, если бы у вас был объект, который определил (скажем)valueOf
с использованием синтаксиса метода, его можно было бы использоватьsuper.valueOf()
для получения значения,Object.prototype.valueOf
которое было бы возвращено (прежде чем предположительно делать что-то еще с ним), тогда как вместо этого должна была бы быть версия ES5Object.prototype.valueOf.call(this)
.Это также означает, что метод имеет ссылку на объект, для которого он был определен, поэтому, если этот объект является временным (например, вы передаете его
Object.assign
как один из исходных объектов), синтаксис метода может означать, что объект сохраняется в памяти, когда в противном случае он мог бы быть сборщиком мусора (если механизм JavaScript не обнаруживает эту ситуацию и не обрабатывает ее, если ни один из методов не используетsuper
).Объявления конструктора и метода в
class
(ES2015 +)ES2015 приносит нам
class
синтаксис, включая объявленные конструкторы и методы:Выше приведены два объявления функций: одно для конструктора, который получает имя
Person
, и другое дляgetFullName
, которому назначена функцияPerson.prototype
.источник
w
просто игнорируется?Говоря о глобальном контексте,
var
оператор и операторFunctionDeclaration
в конце создадут не удаляемое свойство глобального объекта, но значение обоих может быть перезаписано .Тонкое различие между этими двумя способами заключается в том, что при запуске процесса создания переменной (до фактического выполнения кода) все идентификаторы, объявленные с помощью,
var
будут инициализированыundefined
, а те, которые используютсяFunctionDeclaration
с, будут доступны с того момента, например:Назначение
bar
FunctionExpression
происходит до времени выполнения.Глобальное свойство, созданное с помощью a,
FunctionDeclaration
может быть перезаписано без каких-либо проблем, как значение переменной, например:Другое очевидное различие между вашими двумя примерами состоит в том, что первая функция не имеет имени, но вторая имеет его, что может быть очень полезно при отладке (то есть проверке стека вызовов).
Что
foo = function() { alert('hello!'); };
касается вашего отредактированного первого примера ( ), это незадекларированное задание, я настоятельно рекомендую вам всегда использоватьvar
ключевое слово.При присваивании без
var
оператора, если указанный идентификатор не найден в цепочке областей действия, он станет удаляемым свойством глобального объекта.Кроме того, необъявленные назначения выбрасывают в
ReferenceError
ECMAScript 5 в строгом режиме .Должен читать:
Примечание . Этот ответ был объединен с другим вопросом , в котором основное сомнение и неправильное представление со стороны OP заключались в том, что идентификаторы, объявленные с
FunctionDeclaration
, не могут быть перезаписаны, что не соответствует действительности.источник
Два фрагмента кода, которые вы разместили там, будут практически для всех целей вести себя одинаково.
Однако различие в поведении состоит в том, что с первым вариантом (
var functionOne = function() {}
) эта функция может быть вызвана только после этой точки в коде.Во втором варианте (
function functionTwo()
) функция доступна для кода, который выполняется выше, где функция объявлена.Это связано с тем, что в первом варианте функция присваивается переменной
foo
во время выполнения. Во втором случае функция присваивается этому идентификаторуfoo
во время разбора.Больше технической информации
В JavaScript есть три способа определения функций.
eval()
, что имеет свои проблемы.источник
Лучшее объяснение ответа Грега
Почему нет ошибки? Нас всегда учили, что выражения выполняются сверху вниз (??)
Потому что:
Это означает, что код такой:
Обратите внимание, что часть назначений объявлений не была поднята. Поднимается только имя.
Но в случае с объявлениями функций также будет поднято все тело функции :
источник
Другие комментаторы уже рассмотрели семантическое различие двух вариантов выше. Я хотел бы отметить стилистическую разницу: только вариант «присваивания» может установить свойство другого объекта.
Я часто строю модули JavaScript с таким шаблоном:
С этим шаблоном все ваши публичные функции будут использовать присваивание, в то время как ваши частные функции будут использовать объявление.
(Обратите также внимание, что для присваивания требуется точка с запятой после оператора, в то время как объявление запрещает это.)
источник
var foo = function(){...}
синтаксис даже для частных переменных.function window.onload() {}
была вещь.)Иллюстрацией того, когда следует предпочесть первый метод второму, является случай, когда вам нужно избежать переопределения предыдущих определений функции.
С
это определение
myfunction
переопределит любое предыдущее определение, поскольку оно будет выполнено во время синтаксического анализа.Пока
делает правильную работу по определению
myfunction
только тогда, когдаcondition
встречается.источник
var myFunc = null;
вне цикла или вне блока if / elseif / else. Затем вы можете условно назначить разные функции одной и той же переменной. В JS лучше назначить отсутствующее значение для нуля, а затем для неопределенного. Поэтому вы должны сначала объявить myFunction как null, а затем назначить ее позже, условно.Важной причиной является добавление одной и только одной переменной в качестве «корня» вашего пространства имен ...
или
Есть много методов для пространства имен. Это становится все более важным с множеством доступных модулей JavaScript.
Также см. Как мне объявить пространство имен в JavaScript?
источник
Подъем - это действие интерпретатора JavaScript по перемещению всех объявлений переменных и функций в начало текущей области видимости.
Однако, только фактические декларации подняты. оставляя задания там, где они есть.
переменная
Javascript называется свободно типизированным языком. Это означает, что переменные Javascript могут содержать значение любого типа данных . Javascript автоматически заботится об изменении типа переменной на основе значения / литерала, предоставленного во время выполнения.
функция
Возвращаемое значение функции по умолчанию: « undefined », значение объявления переменной по умолчанию также «undefined»
Объявление функции
Выражение функции
Функция, назначенная переменной Пример:
JavaScript интерпретируется как
Вы можете проверить объявление функции, тестирование выражений в разных браузерах, используя
jsperf Test Runner
Классы функций конструктора ES5 : объекты функций, созданные с использованием Function.prototype.bind
JavaScript обрабатывает функции как объекты первого класса, поэтому, будучи объектом, вы можете назначать свойства функции.
В ES6 появилась функция стрелки: выражение функции стрелки имеет более короткий синтаксис, они лучше всего подходят для функций, не относящихся к методам, и их нельзя использовать в качестве конструкторов.
источник
Я добавляю свой собственный ответ только потому, что все остальные подробно рассмотрели подъемную часть.
Я задавался вопросом о том, какой способ лучше долгое время, и благодаря http://jsperf.com теперь я знаю :)
Объявления функций быстрее, и вот что действительно имеет значение в Web Dev, верно? ;)
источник
Объявление функции и выражение функции, присвоенные переменной, ведут себя одинаково после установления привязки.
Однако есть разница в том, как и когда объект функции действительно связан с его переменной. Это различие связано с механизмом, называемым переменным подъемом в JavaScript.
По сути, все объявления функций и объявления переменных выводятся наверх функции, в которой происходит объявление (поэтому мы говорим, что JavaScript имеет область действия функции ).
Когда объявление функции поднято, тело функции «следует», поэтому, когда тело функции вычисляется, переменная будет немедленно привязана к объекту функции.
Когда декларация переменной поднята, инициализация не следует, но "остается позади". Переменная инициализируется
undefined
в начале тела функции, и ей будет присвоено значение в исходном месте в коде. (На самом деле, ему будет присвоено значение в каждом месте, где происходит объявление переменной с тем же именем.)Порядок подъема также важен: объявления функций имеют приоритет над объявлениями переменных с тем же именем, а последнее объявление функции имеет приоритет над предыдущими объявлениями функций с тем же именем.
Некоторые примеры...
Переменная
foo
поднимается к верхней части функции, инициализируетсяundefined
, так что!foo
этоtrue
, такfoo
назначено10
.foo
Внеbar
сферы «S не играет никакой роли и нетронутая.Объявления функций имеют приоритет над объявлениями переменных, а последнее объявление функции «залипает».
В этом примере
a
инициализируется с помощью объекта функции, полученного в результате оценки второго объявления функции, а затем присваивается4
.Здесь сначала поднимается объявление функции, объявляющее и инициализирующее переменную
a
. Далее эта переменная назначается10
. Другими словами: присваивание не присваивается внешней переменнойa
.источник
Первый пример - объявление функции:
Второй пример - это выражение функции:
Главное отличие в том, как они поднимаются (поднимаются и декларируются). В первом примере вся декларация функции поднята. Во втором примере поднимается только переменная 'abc', ее значение (функция) будет неопределенным, а сама функция останется в той позиции, в которой она объявлена.
Проще говоря:
Чтобы узнать больше об этой теме, я настоятельно рекомендую вам эту ссылку
источник
С точки зрения стоимости обслуживания кода, именованные функции являются более предпочтительными:
Я подозреваю, что больше PROS для именованных функций следуют. И то, что перечислено как преимущество именованных функций, является недостатком для анонимных.
Исторически анонимные функции возникали из-за невозможности JavaScript как языка перечислять членов с именованными функциями:
источник
В терминах информатики мы говорим об анонимных функциях и именованных функциях. Я думаю, что наиболее важным отличием является то, что анонимная функция не связана с именем, следовательно, имя анонимной функции. В JavaScript это объект первого класса, динамически объявленный во время выполнения.
Для получения дополнительной информации об анонимных функциях и лямбда-исчислении Википедия является хорошим началом ( http://en.wikipedia.org/wiki/Anonymous_function ).
источник
Я использую переменный подход в своем коде по очень конкретной причине, теория которой была абстрактно рассмотрена выше, но пример может помочь некоторым людям, таким как я, с ограниченным опытом работы с JavaScript.
У меня есть код, который мне нужен для запуска с 160 индивидуально разработанными брендами. Большая часть кода находится в общих файлах, но специфичные для брендинга вещи находятся в отдельном файле, по одному для каждого брендинга.
Некоторые марки требуют определенных функций, а некоторые нет. Иногда мне нужно добавлять новые функции, чтобы делать новые вещи, специфичные для брендинга. Я рад изменить код общего доступа, но мне не нужно менять все 160 наборов фирменных файлов.
Используя синтаксис переменной, я могу объявить переменную (по существу, указатель на функцию) в общем коде и либо назначить тривиальную функцию-заглушку, либо установить значение null.
Одна или две маркировки, которым требуется конкретная реализация функции, могут затем определить свою версию функции и назначить ее переменной, если они хотят, а остальные ничего не делают. Я могу проверить нулевую функцию, прежде чем выполнить ее в общем коде.
Судя по комментариям людей выше, я понимаю, что, возможно, можно также переопределить статическую функцию, но я думаю, что решение для переменной хорошо и понятно.
источник
Ответ Грега достаточно хорош, но я все же хотел бы добавить к нему кое-что, чему я научился только сейчас, наблюдая за Дугласом Крокфордом видеофильмы .
Функциональное выражение:
Оператор функции:
Оператор функции - это просто сокращение для
var
оператора сfunction
значением.Так
расширяется до
Что расширяется дальше:
И они оба поднимаются на вершину кода.
источник
Существует четыре заслуживающих внимания сравнения двух разных объявлений функций, перечисленных ниже.
Следующее работает, потому что
function add()
ограничено до ближайшего блока:Следующее не работает, потому что переменная вызывается перед назначением переменной значения функции
add
.Приведенный выше код по функциональности идентичен приведенному ниже. Обратите внимание, что явное присвоение
add = undefined
является излишним, потому что простое выполнениеvar add;
точно так же, какvar add=undefined
.Следующее не работает, потому что
var add=
superseedsfunction add()
.Имя функции
function thefuncname(){}
является thefuncname , когда она объявлена таким образом.В противном случае, если функция объявлена как
function(){}
, функция .name является первой переменной, используемой для хранения функции.Если для функции не заданы переменные, то именем функции является пустая строка (
""
).Наконец, хотя переменная, которой назначена функция, изначально задает имя, последующие переменные, установленные для функции, не меняют имя.
В Google V8 и Firefox Spidermonkey может быть несколько микросекундных различий в компиляции JIST, но в конечном итоге результат будет точно таким же. Чтобы доказать это, давайте проверим эффективность JSPerf в микробенчмарках, сравнив скорость двух пустых фрагментов кода. В тестах JSPerf найдены здесь . И тесты jsben.ch находятся здесь . Как вы можете видеть, есть заметная разница, когда их не должно быть. Если вы действительно фанат производительности, как я, то, возможно, стоит попытаться уменьшить количество переменных и функций в области и, в частности, устранить полиморфизм (например, использовать одну и ту же переменную для хранения двух разных типов).
Когда вы используете
var
ключевое слово для объявления переменной, вы можете переназначить другое значение этой переменной следующим образом.Однако, когда мы используем оператор const, ссылка на переменную становится неизменной. Это означает, что мы не можем присвоить новое значение переменной. Обратите внимание, однако, что это не делает содержимое переменной неизменным: если вы это сделаете
const arr = []
, вы все равно можете это сделатьarr[10] = "example"
. Только делать что-то вродеarr = "new value"
илиarr = []
будет выдавать ошибку, как показано ниже.Интересно, что если мы объявим переменную как
function funcName(){}
, то неизменность переменной будет такой же, как и при объявлении переменнойvar
.Что такое «Ближайший блок»
«Ближайший блок» является ближайшей «функцией» (включая асинхронные функции, функции генератора и асинхронные функции генератора). Тем не менее, что интересно, a
function functionName() {}
ведет себя какvar functionName = function() {}
когда находится в незамкнутом блоке для элементов за пределами указанного замыкания. Обратите внимание.var add=function(){}
function add(){}
if
,else
,for
,while
,try
/catch
/finally
,switch
,do
/while
,with
)var add=function()
function add()
источник
@EugeneLazutkin приводит пример, где он называет назначенную функцию, которую можно использовать
shortcut()
как внутреннюю ссылку на себя. Джон Резиг приводит другой пример - копирование рекурсивной функции, назначенной другому объекту, в своем обучающем расширенном Javascript пособии по . Хотя назначение функций для свойств здесь не является строго вопросом, я рекомендую активно попробовать учебник - запустите код, нажав кнопку в правом верхнем углу, и дважды щелкните код, чтобы изменить его по своему вкусу.Примеры из учебника: рекурсивные вызовы в
yell()
:Тесты не выполняются, когда оригинальный объект ниндзя удаляется. (страница 13)
Если вы назовете функцию, которая будет вызываться рекурсивно, тесты пройдут. (страница 14)
источник
Другое отличие, которое не упоминается в других ответах, заключается в том, что если вы используете анонимную функцию
и использовать это как конструктор, как в
тогда
one.constructor.name
не будет определяться.Function.name
не является стандартным, но поддерживается Firefox, Chrome, другими браузерами на основе Webkit и IE 9+.С
можно получить имя конструктора в виде строки с
two.constructor.name
.источник
Первый (функция doSomething (x)) должен быть частью нотации объекта.
Второй (
var doSomething = function(x){ alert(x);}
) просто создает анонимную функцию и присваивает ее переменнойdoSomething
. Так что doSomething () вызовет функцию.Вы можете знать , что в объявлении функции и выражение функции есть.
Объявление функции определяет именованную переменную функции без необходимости назначения переменной. Объявления функций выполняются как отдельные конструкции и не могут быть вложены в нефункциональные блоки.
В вышеупомянутом условии имя функции видимо в пределах своей области видимости и области видимости ее родителя (иначе это было бы недоступно).
И в выражении функции
Выражение функции определяет функцию как часть более крупного синтаксиса выражения (обычно присваивание переменной). Функции, определенные через выражения функций, могут быть именованными или анонимными. Выражения функций не должны начинаться с «function».
источник
Я перечисляю различия ниже:
Объявление функции может быть размещено в любом месте кода. Даже если оно вызывается до того, как определение появляется в коде, оно выполняется, когда объявление функции фиксируется в памяти или каким-либо образом, до того, как любой другой код на странице начнет выполнение.
Взгляните на функцию ниже:
Это потому, что во время исполнения это выглядит так:
Выражение функции, если оно не определено перед вызовом, приведет к ошибке. Кроме того, здесь само определение функции не перемещается наверх и не фиксируется в памяти, как в объявлениях функций. Но переменная, которой мы назначаем функцию, поднимается, и ей назначается неопределенная функция .
Та же функция, используя выражения функций:
Это потому, что во время исполнения это выглядит так:
Не безопасно писать объявления функций в нефункциональных блоках, как будто, потому что они не будут доступны.
Выражение именованной функции, подобное приведенному ниже, может не работать в браузерах Internet Explorer до версии 9.
источник
Если бы вы использовали эти функции для создания объектов, вы бы получили:
источник
console.log(objectOne.__proto__);
печатает "functionOne {}" в моей консоли. Любые идеи о том, почему это может иметь место?В свете аргумента «именованные функции отображаются в следах стека» современные движки JavaScript на самом деле вполне способны представлять анонимные функции.
На момент написания этой статьи V8, SpiderMonkey, Chakra и Nitro всегда ссылаются на именованные функции по именам. Они почти всегда ссылаются на анонимную функцию по ее идентификатору, если она есть.
SpiderMonkey может выяснить имя анонимной функции, возвращаемой другой функцией. Остальные не могут.
Если вы действительно хотите, чтобы ваш итератор и обратные вызовы об успешном выполнении отображались в трассировке, вы могли бы назвать их тоже ...
Но по большей части это не стоит переоценивать.
Жгут ( Скрипка )
V8
SpiderMonkey
чакра
Nitro
источник
В JavaScript есть два способа создания функций:
Объявление функции:
Это очень простой, не требующий пояснений, используемый на многих языках и стандартный для всей семьи языков C. Мы объявили функцию, определили ее и выполнили, вызвав ее.
Что вы должны знать, так это то, что функции на самом деле являются объектами в JavaScript; внутренне мы создали объект для вышеуказанной функции и дали ему имя с именем fn, или ссылка на объект сохраняется в fn. Функции являются объектами в JavaScript; экземпляр функции на самом деле является экземпляром объекта.
Функциональное выражение:
JavaScript имеет первоклассные функции, то есть создает функцию и присваивает ее переменной так же, как вы создаете строку или число и присваиваете ее переменной. Здесь переменная fn назначается функции. Причиной этого понятия являются функции в JavaScript; fn указывает на экземпляр объекта вышеуказанной функции. Мы инициализировали функцию и присвоили ее переменной. Это не выполнение функции и присвоение результата.
Ссылка: Синтаксис объявления функции JavaScript: var fn = function () {} против функции fn () {}
источник
var fn = function fn() {...}
?Оба являются разными способами определения функции. Разница в том, как браузер интерпретирует и загружает их в контекст выполнения.
Первый случай - это выражения функций, которые загружаются только тогда, когда интерпретатор достигает этой строки кода. Поэтому, если вы сделаете это, как показано ниже, вы получите ошибку, что functionOne не является функцией .
Причина в том, что в первой строке никакое значение не назначено для functionOne, и, следовательно, оно не определено. Мы пытаемся вызвать его как функцию и, следовательно, получаем ошибку.
Во второй строке мы присваиваем ссылку на анонимную функцию для functionOne.
Второй случай - это объявления функций, которые загружаются перед выполнением любого кода. Поэтому, если вам нравится следующее, вы не получите никакой ошибки, поскольку объявление загружается до выполнения кода.
источник
О производительности:
Новые версии
V8
представили несколько скрытых оптимизаций, что и сделалиSpiderMonkey
.Теперь почти нет разницы между выражением и объявлением.
Выражение функции теперь выглядит быстрее .
Chrome 62.0.3202
FireFox 55
Хром Канарейка 63.0.3225
Firefox Chrome Канарейка Хром
источник
Они очень похожи с некоторыми небольшими отличиями: первая - это переменная, которая назначена анонимной функции (объявление функции), а вторая - нормальный способ создания функции в JavaScript (объявление анонимной функции), у обоих есть использование, минусы и плюсы. :
1. Выражение функции
Присвоение переменной функции означает, что никакой Hoisting, поскольку мы знаем, что функции в JavaScript могут Hoist, означает, что они могут быть вызваны до того, как они будут объявлены, в то время как переменные должны быть объявлены до получения доступа к ним, поэтому в этом случае мы не можем доступ к функции до того, как она объявлена, также это может быть способ написания ваших функций, для функций, которые возвращают другую функцию, такое объявление может иметь смысл, также в ECMA6 и выше вы можете назначить это функции стрелки, которая может использоваться для вызова анонимных функций, также этот способ объявления является лучшим способом создания функций конструктора в JavaScript.
2. Объявление функций
Это нормальный способ вызова функции в JavaScript, эта функция может быть вызвана еще до того, как вы объявите ее, поскольку в JavaScript все функции получают Hoisted, но если вы используете 'строгий', это не будет Hoist, как ожидалось, это хороший способ вызывать все нормальные функции, которые не большие по строкам и не являются функциями-конструкторами.
Кроме того, если вам нужна дополнительная информация о том, как работает подъем в JavaScript, перейдите по ссылке ниже:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
источник
...also this way of declaring is a better way to create Constructor functions in JavaScript
Прошу уточнить, мне любопытно!Это всего лишь два возможных способа объявления функций, а во-вторых, вы можете использовать функцию перед объявлением.
источник
new Function()
может использоваться для передачи тела функции в строку. И, следовательно, это может быть использовано для создания динамических функций. Также передача сценария без выполнения сценария.источник