it-roy-ru.com

var functionName = function () {} против функции functionName () {}

Недавно я начал поддерживать чужой код JavaScript. Я исправляю ошибки, добавляю функции, а также пытаюсь привести код в порядок и сделать его более согласованным.

Предыдущий разработчик использовал два способа объявления функций, и я не могу понять, есть ли причина этого или нет.

Два способа:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

Каковы причины использования этих двух разных методов и каковы плюсы и минусы каждого? Есть ли что-нибудь, что можно сделать одним методом, но нельзя сделать другим?

6315
Richard Garside

Различие состоит в том, что functionOne является выражением функции и поэтому определяется только при достижении этой строки, тогда как functionTwo является объявлением функции и определяется, как только выполняется его окружающая функция или скрипт (из-за hoisting ). 

Например, выражение функции:

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

И объявление функции: 

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

Это также означает, что вы не можете условно определять функции, используя объявления функций:

if (test) {
   // Error or misbehavior
   function functionThree() { doSomething(); }
}

Выше фактически определяет functionThree независимо от значения test - если только use strict не действует, в этом случае он просто вызывает ошибку.

4694
Greg

Сначала я хочу исправить Грега: function abc(){} также ограничена - имя abc определено в области, где встречается это определение. Пример:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

Во-вторых, можно сочетать оба стиля:

var xyz = function abc(){};

xyz будет определен как обычно, abc не определен во всех браузерах, кроме Internet Explorer - не полагайтесь на его определение. Но это будет определено внутри его тела:

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

Если вы хотите использовать псевдонимы для всех браузеров, используйте этот вид объявления:

function abc(){};
var xyz = abc;

В этом случае и xyz, и abc являются псевдонимами одного и того же объекта:

console.log(xyz === abc); // prints "true"

Одной из веских причин для использования комбинированного стиля является атрибут «имя» функциональных объектов ( не поддерживается Internet Explorer ). В основном, когда вы определяете функцию, как

function abc(){};
console.log(abc.name); // prints "abc"

его имя присваивается автоматически. Но когда вы определяете это как

var abc = function(){};
console.log(abc.name); // prints ""

его имя пустое - мы создали анонимную функцию и присвоили ее некоторой переменной.

Еще одна веская причина для использования комбинированного стиля - использовать короткое внутреннее имя для ссылки на себя, предоставляя длинное не конфликтующее имя для внешних пользователей:

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

В приведенном выше примере мы можем сделать то же самое с внешним именем, но оно будет слишком громоздким (и медленным).

(Другой способ сослаться на себя - использовать arguments.callee, который все еще относительно длинный и не поддерживается в строгом режиме.)

В глубине души JavaScript обрабатывает оба утверждения по-разному. Это объявление функции:

function abc(){}

abc здесь определяется везде в текущей области видимости:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

Кроме того, он поднялся через оператор return:

// We can call it here
abc(); // Works
return;
function abc(){}

Это функциональное выражение:

var xyz = function(){};

xyz здесь определяется с точки назначения:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

Объявление функции в сравнении с выражением функции является реальной причиной, по которой Грег демонстрирует разницу.

Интересный факт:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

Лично я предпочитаю объявление «выражение функции», потому что таким образом я могу контролировать видимость. Когда я определяю функцию как

var abc = function(){};

Я знаю, что я определил функцию локально. Когда я определяю функцию как

abc = function(){};

Я знаю, что я определил это глобально, при условии, что я не определил abc нигде в цепочке областей. Этот стиль определения устойчив, даже когда используется внутри eval(). Хотя определение

function abc(){};

зависит от контекста и может заставить вас угадать, где он определен, особенно в случае eval() - ответ таков: это зависит от браузера.

1853
Eugene Lazutkin

Вот краткое изложение стандартных форм, которые создают функции: (Первоначально написано для другого вопроса, но адаптировано после перемещения в канонический вопрос.)

Термины:

Быстрый список:

  • Объявление функции

  • «Anonymous» function Выражение (которое, несмотря на термин, иногда создает функции с именами)

  • Именное function Выражение

  • Инициализатор функций доступа (ES5 +)

  • Выражение функции стрелки (ES2015 +) (которое, как и выражения анонимной функции, не содержит явного имени и может создавать функции с именами)

  • Объявление метода в инициализаторе объекта (ES2015 +)

  • Объявления конструктора и метода в class (ES2015 +)

Объявление функции

Первая форма - это объявление функции, которая выглядит следующим образом:

function x() {
    console.log('x');
}

Объявление функции - это объявление; это не утверждение или выражение. Таким образом, вы не следуете ; (хотя это безвредно).

Объявление функции обрабатывается, когда выполнение входит в контекст, в котором оно появляется, перед выполняется любой пошаговый код. Создаваемой ей функции присваивается собственное имя (x в примере выше), и это имя помещается в область, в которой появляется объявление.

Поскольку он обрабатывается перед любым пошаговым кодом в том же контексте, вы можете сделать что-то вроде этого:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

До ES2015 спецификация не охватывала то, что должен делать движок JavaScript, если вы помещаете объявление функции в управляющую структуру, такую ​​как try, if, switch, while и т.д., Например:

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

И поскольку они обрабатываются before пошаговый код запускается, сложно знать, что делать, когда они находятся в управляющей структуре.

Хотя делать это не было указано до ES2015, это было допустимое расширение для поддержки объявлений функций в блоках. К сожалению (и неизбежно), разные двигатели делали разные вещи.

Начиная с ES2015, в спецификации сказано, что делать. Фактически, это дает три отдельных действия:

  1. Если в свободном режиме not в веб-браузере, движок JavaScript должен делать одно
  2. Если в свободном режиме в веб-браузере, движок JavaScript должен делать что-то еще
  3. Если в режиме строго (браузер или нет), движок JavaScript должен делать еще одну вещь

Правила для свободных режимов хитры, но в режиме строго объявления функций в блоках просты: они локальны для блока (у них есть область видимости блока, что также ново в ES2015), и они поднимаются на вершину блока. Так:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

Выражение "Anonymous" function

Вторая общая форма называется выражение анонимной функции:

var y = function () {
    console.log('y');
};

Как и все выражения, оно оценивается, когда достигается при пошаговом выполнении кода.

В ES5 созданная функция не имеет имени (она анонимна). В ES2015, функции по возможности присваивается имя, выводя его из контекста. В приведенном выше примере имя будет y. Нечто подобное происходит, когда функция является значением инициализатора свойства. (Для получения подробной информации о том, когда это происходит, и о правилах, найдите SetFunctionName в спецификации - он появляется во всем месте.)

Именное function Выражение

Третья форма - это именованное выражение функции ("NFE"):

var z = function w() {
    console.log('zw')
};

Функция, которую она создает, имеет правильное имя (в данном случае w). Как и все выражения, это оценивается, когда оно достигается при пошаговом выполнении кода. Имя функции not добавлено в область, в которой появляется выражение; имя is в области действия самой функции:

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

Обратите внимание, что NFE часто являются источником ошибок для реализаций JavaScript. Например, IE8 и более ранние версии обрабатывают NFEs совершенно неправильно , создавая две разные функции в два разных момента времени. Ранние версии Safari также имели проблемы. Хорошей новостью является то, что в текущих версиях браузеров (IE9 и выше, текущий Safari) таких проблем больше нет. (К сожалению, на момент написания этой статьи IE8 все еще широко используется, и поэтому использование NFE с кодом для Интернета в целом все еще проблематично.)

Инициализатор функций доступа (ES5 +)

Иногда функции могут проникнуть в значительной степени незамеченными; это так с функции доступа. Вот пример:

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

Обратите внимание, что когда я использовал эту функцию, я не использовал ()! Это потому что это функция доступа для свойства. Мы получаем и устанавливаем свойство обычным способом, но за кулисами вызывается функция.

Вы также можете создавать функции доступа с Object.defineProperty, Object.defineProperties и менее известным вторым аргументом Object.create.

Выражение функции стрелки (ES2015 +)

ES2015 приносит нам функция стрелки. Вот один пример:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

Видите, что n => n * 2 скрывается в вызове map()? Это функция.

Несколько вещей о функциях стрелок:

  1. У них нет своих this. Вместо этого они закрываютthis контекста, в котором они определены. (Они также закрывают arguments и, где необходимо, super.) Это означает, что this внутри них совпадает с this, где они были созданы, и не может быть изменена.

  2. Как вы уже заметили, вы не используете ключевое слово function; вместо этого вы используете =>.

Пример n => n * 2, приведенный выше, является одной из них. Если у вас есть несколько аргументов для передачи функции, вы используете parens:

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

(Помните, что Array#map передает запись в качестве первого аргумента, а индекс - в качестве второго.)

В обоих случаях тело функции является просто выражением; возвращаемое значение функции будет автоматически результатом этого выражения (вы не используете явное return).

Если вы делаете больше, чем просто одно выражение, используйте {} и явную return (если вам нужно вернуть значение), как обычно:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

Версия без { ... } называется функцией стрелки с тело выражения или краткое тело. (Также: функция стрелки A краткая.) Функция, в которой { ... } определяет тело, является функцией стрелки с тело функции. (Также: функция стрелки A подробный.)

Объявление метода в инициализаторе объекта (ES2015 +)

ES2015 допускает более короткую форму объявления свойства, которое ссылается на функцию, называемую определение метода; это выглядит так:

var o = {
    foo() {
    }
};

почти эквивалент в ES5 и более ранних версиях:

var o = {
    foo: function foo() {
    }
};

разница (кроме многословия) в том, что метод может использовать super, а функция - нет. Так, например, если бы у вас был объект, который определил (скажем) valueOf с использованием синтаксиса метода, он мог бы использовать super.valueOf(), чтобы получить значение, которое Object.prototype.valueOf возвратил бы (прежде чем предположительно делать что-то еще с ним), тогда как версия ES5 должна была бы выполнить Object.prototype.valueOf.call(this) вместо.

Это также означает, что метод имеет ссылку на объект, для которого он был определен, поэтому, если этот объект является временным (например, вы передаете его в Object.assign как один из исходных объектов), синтаксис метода могло бы означает, что объект сохраняется в памяти, если в противном случае он мог бы быть собран сборщиком мусора (если механизм JavaScript не обнаруживает эту ситуацию и не обрабатывает ее, если ни один из методов не использует super).

Объявления конструктора и метода в class (ES2015 +)

ES2015 предоставляет нам синтаксис class, включая объявленные конструкторы и методы:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Выше приведены два объявления функций: одно для конструктора, который получает имя Person, и одно для getFullName, которое является функцией, назначенной для Person.prototype.

580
T.J. Crowder

Если говорить о глобальном контексте, то и оператор var, и FunctionDeclaration в конце создадут свойство не удаляемое для глобального объекта, но значение обоих может быть перезаписано.

Тонкое различие между этими двумя способами заключается в том, что при запуске процесса Variable Instantiation (до фактического выполнения кода) все идентификаторы, объявленные с помощью var, будут инициализированы с помощью undefined, а те, которые используются FunctionDeclaration, будут доступны с этого момента. , например:

 alert(typeof foo); // 'function', it's already available
 alert(typeof bar); // 'undefined'
 function foo () {}
 var bar = function () {};
 alert(typeof bar); // 'function'

Назначение barFunctionExpression происходит до времени выполнения.

Глобальное свойство, созданное переменной FunctionDeclaration, может быть без проблем перезаписано, как и значение переменной, например:

 function test () {}
 test = null;

Другое очевидное различие между вашими двумя примерами состоит в том, что первая функция не имеет имени, но вторая имеет его, что может быть очень полезно при отладке (то есть проверке стека вызовов).

Что касается вашего отредактированного первого примера (foo = function() { alert('hello!'); };), это необъявленное назначение, я настоятельно рекомендую вам всегда использовать ключевое слово var.

При назначении, без оператора var, если указанный идентификатор не найден в цепочке областей действия, он станет свойством deleteable глобального объекта.

Кроме того, необъявленные назначения выдают ReferenceError в ECMAScript 5 в строгом режиме .

Должен читать:

Примечание : Этот ответ был объединен с другим вопросом , в котором основное сомнение и неправильное представление со стороны OP заключались в том, что идентификаторы, объявленные с FunctionDeclaration, не могут быть перезаписаны, что не соответствует действительности.

138
CMS

Два фрагмента кода, которые вы разместили там, будут практически для всех целей вести себя одинаково.

Однако разница в поведении заключается в том, что в первом варианте (var functionOne = function() {}) эта функция может вызываться только после этой точки в коде.

Во втором варианте (function functionTwo()) функция доступна для кода, который выполняется выше, где функция объявлена.

Это связано с тем, что в первом варианте функция назначается переменной foo во время выполнения. Во втором случае функция присваивается этому идентификатору foo во время разбора.

Больше технической информации

В JavaScript есть три способа определения функций.

  1. Ваш первый фрагмент показывает выражение функции . Это включает использование оператора "function" для создания функции - результат этого оператора может быть сохранен в любой переменной или свойстве объекта. Таким образом, выражение функции является мощным. Выражение функции часто называют «анонимной функцией», потому что оно не обязательно должно иметь имя,
  2. Ваш второй пример - объявление функции . Это использует оператор "function" для создания функции. Функция становится доступной во время анализа и может вызываться в любом месте этой области. Вы все еще можете сохранить его в переменной или свойстве объекта позже.
  3. Третий способ определения функции - это конструктор «Function ()» , который не показан в вашем исходном посте. Не рекомендуется использовать это, так как он работает так же, как eval(), у которого есть свои проблемы.
116
thomasrutter

Лучшее объяснение ответ Грега

functionTwo();
function functionTwo() {
}

Почему нет ошибки? Нас всегда учили, что выражения выполняются сверху вниз (??)

Так как:

Декларации функций и объявления переменных всегда перемещаются (hoisted) незаметно в верхнюю часть их содержащей области действия интерпретатором JavaScript. Параметры функций и определяемые языком имена, очевидно, уже есть. Бен вишня

Это означает, что код такой:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

Обратите внимание, что часть назначений объявлений не была поднята. Поднимается только имя.

Но в случае с объявлениями функций все тело функции также будет поднято:

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
97
simple_human

Другие комментаторы уже рассмотрели семантическое различие двух вариантов выше. Я хотел бы отметить стилистическую разницу: только вариант «назначение» может установить свойство другого объекта.

Я часто строю модули JavaScript с таким шаблоном:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

С этим шаблоном все ваши публичные функции будут использовать присваивание, в то время как ваши частные функции будут использовать объявление.

(Обратите также внимание, что для присваивания требуется точка с запятой после оператора, в то время как объявление запрещает это.)

88
Sean McMillan

Иллюстрацией того, когда следует предпочесть первый метод второму, является случай, когда вам нужно избежать переопределения предыдущих определений функции.

С

if (condition){
    function myfunction(){
        // Some code
    }
}

это определение myfunction переопределит любое предыдущее определение, так как оно будет выполнено во время анализа.

В то время как

if (condition){
    var myfunction = function (){
        // Some code
    }
}

выполняет правильную работу по определению myfunction только когда встречается condition.

74
Mbengue Assane

Важной причиной является добавление одной и только одной переменной в качестве «корня» вашего пространства имен ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

или же

var MyNamespace = {
  foo: function() {
  },
  ...
}

Есть много методов для пространства имен. Это становится более важным с множеством доступных модулей JavaScript.

Также см. КАК ОБЪЯВИТЬ ПРОСТРАНСТВО ИМЕН В JAVASCRIPT?

60
Rob

Подъемэто действие интерпретатора JavaScript по перемещению всех объявлений переменных и функций в начало текущей области видимости. 

Тем не менее, только фактические объявления поднимаются. Оставляя назначения там, где они есть.

  • переменные/функции, объявленные внутри страницы, имеют глобальный доступ к любой точке этой страницы.
  • переменные/функции, объявленные внутри функции, имеют локальную область видимости. означает, что они доступны/доступны внутри тела функции (области действия), они не доступны вне тела функции.

Переменная

Javascript называется свободно типизированным языком. Это означает, что переменные Javascript могут содержать значение любого типа данных . Javascript автоматически позаботится об изменении типа переменной на основе значения/литерала, предоставленного во время выполнения.

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777;« Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

Функция

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • функции, объявленные внутри страницы, поднимаются в верхнюю часть страницы, имеющей глобальный доступ.
  • функции, объявленные внутри функционального блока, поднимаются в верхнюю часть блока.
  • По умолчанию возвращаемое значение функции ' undefined ', Variable объявление значения по умолчанию также 'undefined'

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.
    

Объявление функции

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

Выражение функции

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

Функция, назначенная переменной Example:

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

var anonymous = function (){
    console.log('anonymous function Expression');
};

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

javaScript интерпретируется как

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

Вы можете проверить объявление функции, проверку выражения в разных браузерах, используя jsperf Test Runner


Классы функций конструктора ES5 : Объекты функций, созданные с использованием Function.prototype.bind

JavaScript обрабатывает функции как объекты первого класса, поэтому, будучи объектом, вы можете назначать свойства функции.

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

ES6 представил Функция стрелки : Выражение функции стрелки имеет более короткий синтаксис, они лучше всего подходят для функций, не относящихся к методам, и их нельзя использовать в качестве конструкторов.

ArrowFunction : ArrowParameters => ConciseBody .

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd
52
Yash

Я добавляю свой собственный ответ только потому, что все остальные подробно рассмотрели подъемную часть.

Я задавался вопросом о том, какой способ лучше долгое время, и благодаря http://jsperf.com теперь я знаю :)

enter image description here

Объявления функций быстрее, и вот что действительно имеет значение в web dev, верно? ;)

36
Leon Gaban

Объявление функции и выражение функции, присвоенные переменной, ведут себя одинаково после установления привязки.

Однако есть разница в как и когда объект функции фактически связан с его переменной. Это различие связано с механизмом подъема переменной в JavaScript.

По сути, все объявления функций и объявления переменных поднимаются в начало функции , в которой происходит объявление (поэтому мы говорим, что JavaScript имеет область действия функции ).

  • Когда объявление функции поднято, тело функции «следует» , Поэтому, когда тело функции вычисляется, переменная немедленно Будет привязана к объекту функции.

  • Когда декларация переменной поднята, инициализация следует не , Но остается "позади". Переменная инициализируется как undefined в начале тела функции, и ей будет присвоено Значение в исходном месте кода. (На самом деле, ему будет присвоено значение в каждом месте, где происходит объявление переменной с тем же именем.)

Порядок подъема также важен: объявления функций имеют приоритет над объявлениями переменных с тем же именем, а последнее объявление функции имеет приоритет над предыдущими объявлениями функций с тем же именем.

Некоторые примеры...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

Переменная foo поднимается в верхнюю часть функции, инициализируется как undefined, так что !foo является true, поэтому foo назначается 10. foo вне области действия bar не играет никакой роли и остается нетронутой. 

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

Объявления функций имеют приоритет над объявлениями переменных, а последнее объявление функции «залипает».

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

В этом примере a инициализируется объектом функции, полученным в результате вычисления второго объявления функции, а затем присваивается 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

Здесь сначала поднимается объявление функции, объявляя и инициализируя переменную a. Далее этой переменной присваивается 10. Другими словами: присваивание не присваивается внешней переменной a.

32
eljenso

Первый пример - объявление функции:

function abc(){}

Второй пример - это выражение функции:

var abc = function() {};

Основное отличие заключается в том, как они поднимаются (поднимаются и декларируются). В первом примере вся декларация функции поднята. Во втором примере поднимается только переменная abc, ее значение (функция) будет неопределенным, а сама функция останется в той позиции, в которой она объявлена.

Проще говоря:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

Чтобы узнать больше об этой теме, я настоятельно рекомендую вам эту ссылку

30
sla55er

С точки зрения стоимости обслуживания кода, именованные функции являются более предпочтительными:

  • Независимо от места, где они объявлены (но все еще ограничены областью действия).
  • Более устойчивы к ошибкам, таким как условная инициализация (вы все равно можете переопределить, если хотите).
  • Код становится более читабельным благодаря выделению локальных функций отдельно от функциональности области. Обычно в области действия сначала идет функциональность, за которой следуют объявления локальных функций.
  • В отладчике вы четко увидите имя функции в стеке вызовов вместо «анонимной/оцененной» функции.

Я подозреваю, что больше PROS для именованных функций следуют. И то, что перечислено как преимущество именованных функций, является недостатком для анонимных.

Исторически анонимные функции возникали из-за невозможности JavaScript как языка перечислять членов с именованными функциями:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
28
Sasha Firsov

Я использую переменный подход в своем коде по очень конкретной причине, теория которой была абстрактно рассмотрена выше, но пример может помочь некоторым людям, таким как я, с ограниченным опытом работы с JavaScript.

У меня есть код, который мне нужен для запуска с 160 индивидуально разработанными брендами. Большая часть кода находится в общих файлах, но специфические для брендинга вещи находятся в отдельном файле, по одному для каждого брендинга.

Некоторые бренды требуют определенных функций, а некоторые нет. Иногда мне нужно добавлять новые функции, чтобы делать новые вещи, специфичные для брендинга. Я рад изменить код общего доступа, но я не хочу менять все 160 наборов фирменных файлов.

Используя синтаксис переменной, я могу объявить переменную (по существу, указатель на функцию) в общем коде и либо назначить тривиальную функцию-заглушку, либо установить значение null.

Одна или две маркировки, которым требуется конкретная реализация функции, могут затем определить свою версию функции и назначить ее переменной, если они хотят, а остальные ничего не делают. Я могу проверить нулевую функцию, прежде чем выполнить ее в общем коде.

Судя по комментариям людей выше, я понимаю, что, возможно, можно также переопределить статическую функцию, но я думаю, что решение с переменной является хорошим и понятным.

24
Herc

В терминах информатики мы говорим об анонимных функциях и именованных функциях. Я думаю, что наиболее важным отличием является то, что анонимная функция не связана с именем, следовательно, имя анонимной функции. В JavaScript это объект первого класса, динамически объявленный во время выполнения.

Дополнительную информацию об анонимных функциях и лямбда-исчислении можно найти в Википедии ( http://en.wikipedia.org/wiki/Anonymous_function ).

22
Kafka

Ответ Грега достаточно хорош, но я все же хотел бы добавить к нему кое-что, чему я научился только сейчас, просматривая видео Дугласа Крокфорда .

Выражение функции:

var foo = function foo() {};

Оператор функции:

function foo() {};

Оператор function - это просто сокращение для оператора var со значением function.

Так

function foo() {};

расширяется до

var foo = function foo() {};

Что расширяется дальше:

var foo = undefined;
foo = function foo() {};

И они оба поднимаются на вершину кода.

Screenshot from video

22
Rohan

@EugeneLazutkin приводит пример, где он называет назначенную функцию, чтобы иметь возможность использовать shortcut() как внутреннюю ссылку на себя. Джон Резиг приводит другой пример - копирование рекурсивной функции, назначенной другому объекту в его Учебное пособие по расширенному Javascript . Хотя назначение функций для свойств здесь не является строго вопросом, я рекомендую активно опробовать учебное пособие - запустите код, нажав кнопку в правом верхнем углу, и дважды щелкните код, чтобы изменить его по своему вкусу.

Примеры из учебника: рекурсивные вызовы в yell():

Тесты не пройдены, когда оригинальный объект ниндзя удаляется. (стр. 13)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

Если вы назовете функцию, которая будет вызываться рекурсивно, тесты пройдут. (стр. 14)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
18
Joel Purra

Другое отличие, которое не упоминается в других ответах, заключается в том, что если вы используете анонимную функцию

var functionOne = function() {
    // Some code
};

и использовать это как конструктор, как в

var one = new functionOne();

тогда one.constructor.name не будет определен. Function.name не является стандартным, но поддерживается Firefox, Chrome, другими браузерами, созданными на основе Webkit, и IE 9+.

С 

function functionTwo() {
    // Some code
}
two = new functionTwo();

можно получить имя конструктора в виде строки с помощью two.constructor.name.

16
Ingo Kegel

Первый (функция doSomething (x)) должен быть частью нотации объекта.

Второй (var doSomething = function(x){ alert(x);}) - это просто создание анонимной функции и присвоение ее переменной doSomething. Так что doSomething () вызовет функцию.

Возможно, вы захотите узнать, что такое объявление функции и выражение функции .

Объявление функции определяет именованную переменную функции без необходимости назначения переменной. Объявления функций выполняются как отдельные конструкции и не могут быть вложены в нефункциональные блоки.

function foo() {
    return 3;
}

ECMA 5 (13.0) определяет синтаксис как 
Идентификатор функции (FormalParameterListopt ) {FunctionBody}

В вышеупомянутом условии имя функции видимо в пределах своей области видимости и области видимости ее родителя (в противном случае оно было бы недоступно).

И в выражении функции

Выражение функции определяет функцию как часть более крупного синтаксиса выражения (обычно присваивание переменной). Функции, определенные через выражения функций, могут быть именованными или анонимными. Выражения функций не должны начинаться с «function».

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5 (13.0) определяет синтаксис как 
Идентификатор функцииopt (FormalParameterListopt ) {FunctionBody}

14
NullPoiиteя

Если бы вы использовали эти функции для создания объектов, вы бы получили:

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
14
Pawel Furmaniak

Я перечисляю различия ниже:

  1. Объявление функции может быть размещено в любом месте кода. Даже если оно вызывается до того, как определение появляется в коде, оно выполняется, когда объявление функции фиксируется в памяти или каким-либо образом, до того, как любой другой код на странице начнет выполнение.

    Посмотрите на функцию ниже:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2
    

    Это потому, что во время исполнения это выглядит так:

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed
    

    Выражение функции, если оно не определено перед вызовом, приведет к ошибке. Кроме того, здесь само определение функции не перемещается наверх и не фиксируется в памяти, как в объявлениях функций. Но переменная, которой мы назначаем функцию, поднимается и undefined присваивается ей.

    Та же функция, используя выражения функций:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1
    

    Это потому, что во время выполнения это выглядит так:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
    
  2. Писать объявления функций в нефункциональных блоках, таких как if , небезопасно, потому что они не будут доступны.

    if (test) {
        function x() { doSomething(); }
    }
    
  3. Выражение именованной функции, подобное приведенному ниже, может не работать в браузерах Internet Explorer до версии 9.

    var today = function today() {return new Date()}
    
14
varna

В свете аргумента «именованные функции отображаются в следах стека» современные движки JavaScript на самом деле вполне способны представлять анонимные функции.

На момент написания этой статьи V8, SpiderMonkey, Chakra и Nitro всегда ссылаются на именованные функции по именам. Они почти всегда ссылаются на анонимную функцию по ее идентификатору, если она есть.

SpiderMonkey может выяснить имя анонимной функции, возвращаемой другой функцией. Остальные не могут.

Если вы действительно хотите, чтобы ваш итератор и обратные вызовы об успешном выполнении отображались в трассировке, вы могли бы назвать их тоже ...

[].forEach(function iterator() {});

Но по большей части это не стоит переоценивать.

Жгут ( Fiddle )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

SpiderMonkey

func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
[email protected]://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
[email protected]://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
[email protected]://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
[email protected]://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
[email protected]://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

Чакра

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

Nitro

func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: 
Trace:
[email protected]://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: j
Trace:
[email protected]://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: l
Trace:
[email protected]://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: n
Trace:
[email protected]://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: p
Trace:
[email protected]://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33
12
Jackson

Существует четыре заслуживающих внимания сравнения между двумя различными объявлениями функций, перечисленными ниже. 

  1. Наличие (объем) функции

Следующее работает, потому что function add() находится в пределах ближайшего блока:

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

Следующее не работает (потому что var add= заменяет function add()).

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

Следующее не работает, потому что add объявляется после его использования.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

  1. (функция) . имя

Имя функции function thefuncname(){} - thefuncname , когда она объявлена ​​таким образом.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

В противном случае, если функция объявлена ​​как function(){}, function . Name - это первая переменная, используемая для хранения функции.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

Если для функции не заданы переменные, то именем функции является пустая строка ("").

console.log((function(){}).name === "");

Наконец, хотя переменная, которой назначена функция, изначально задает имя, последующие переменные, установленные для функции, не изменяют имя.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. Спектакль

В Google V8 и Firefox Spidermonkey может быть несколько микросекундных различий в компиляции JIST, но в конечном итоге результат будет точно таким же. Чтобы доказать это, давайте рассмотрим эффективность JSPerf в микробенчмарках, сравнив скорость двух пустых фрагментов кода. Тесты JSPerf находятся здесь . И, jsben.ch тесты находятся здесь . Как видите, есть заметная разница, когда их не должно быть. Если вы действительно фанат производительности, как я, то, возможно, стоит попытаться уменьшить количество переменных и функций в области и, в частности, устранить полиморфизм (например, использовать одну и ту же переменную для хранения двух разных типов).

  1. Изменчивость изменчивости

Когда вы используете ключевое слово var для объявления переменной, вы можете переназначить другое значение этой переменной следующим образом.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Однако, когда мы используем оператор const, ссылка на переменную становится неизменной. Это означает, что мы не можем присвоить новое значение переменной. Обратите внимание, однако, что это не делает содержимое переменной неизменным: если вы делаете const arr = [], то вы все равно можете делать arr[10] = "example". Только выполнение таких действий, как arr = "new value" или arr = [], приведет к ошибке, как показано ниже.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Интересно, что если мы объявим переменную как function funcName(){}, то неизменность переменной будет такой же, как и объявление ее с var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Что такое "Ближайший блок"

«Ближайший блок» является ближайшей «функцией» (включая асинхронные функции, функции генератора и асинхронные функции генератора). Тем не менее, что интересно, функция function functionName() {} ведет себя как функция var functionName = function() {}, когда находится в незамкнутом блоке для элементов вне указанного замыкания. Обратите внимание.

  • Нормальная var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • Нормальная function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • Функция

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • Оператор (например, if, else, for, while, try/catch/finally, switch, do/while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • Стрелка Функция с var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • Функция стрелки с function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();

11
Jack Giffin

В JavaScript есть два способа создания функций:

  1. Объявление функции:

    function fn(){
      console.log("Hello");
    }
    fn();
    

    Это очень простой, не требующий пояснений, используемый во многих языках и стандартный для всех языков семейства C. Мы объявили функцию, определили ее и выполнили, вызвав ее.

    Что вы должны знать, так это то, что функции на самом деле являются объектами в JavaScript; внутренне мы создали объект для вышеуказанной функции и дали ему имя с именем fn, или ссылка на объект хранится в fn. Функции являются объектами в JavaScript; экземпляр функции на самом деле является экземпляром объекта.

  2. Функциональное выражение:

    var fn=function(){
      console.log("Hello");
    }
    fn();
    

    JavaScript имеет первоклассные функции, то есть создает функцию и присваивает ее переменной так же, как вы создаете строку или число и присваиваете ее переменной. Здесь переменная fn назначается функции. Причиной этого понятия являются функции в JavaScript; fn указывает на экземпляр объекта вышеуказанной функции. Мы инициализировали функцию и присвоили ее переменной. Это не выполнение функции и присвоение результата.

Ссылка:Синтаксис объявления функции JavaScript: var fn = function () {} против функции fn () {}

10
Anoop Rai

Оба являются разными способами определения функции. Разница в том, как браузер интерпретирует и загружает их в контекст выполнения. 

Первый случай - это выражения функций, которые загружаются только тогда, когда интерпретатор достигает этой строки кода. Поэтому, если вы сделаете это следующим образом, вы получите ошибку, что functionOne не является функцией .

functionOne();
var functionOne = function() {
    // Some code
};

Причина в том, что в первой строке никакое значение не назначено для functionOne, и, следовательно, оно не определено. Мы пытаемся вызвать его как функцию и, следовательно, получаем ошибку.

Во второй строке мы присваиваем ссылку на анонимную функцию для functionOne.

Второй случай - это объявления функций, которые загружаются перед выполнением любого кода. Поэтому, если вам нравится следующее, вы не получите никакой ошибки, поскольку объявление загружается до выполнения кода.

functionOne();
function functionOne() {
   // Some code
}
8
Nitin9791

О производительности:

Новые версии V8 представили несколько внутренних оптимизаций, как и SpiderMonkey.

Теперь почти нет разницы между выражением и объявлением. 
Выражение функции кажется быстрее сейчас.

Chrome 62.0.3202 Chrome test

FireFox 55 Firefox test

Chrome Canary 63.0.3225 Chrome Canary test


Выражения функций Anonymousкажется, имеют лучшую производительность против выражений функций Named.


Firefox Firefox named_anonymous Chrome Canary Chrome canary named_anonymous Chrome Chrome named_anonymous

8
Panos Kal.

Они очень похожи с некоторыми небольшими отличиями: первая - это переменная, которая назначена анонимной функции (объявление функции), а вторая - нормальный способ создания функции в JavaScript (объявление анонимной функции), у обоих есть использование, минусы и плюсы. :

1. Выражение функции

var functionOne = function() {
    // Some code
};

Выражение функции определяет функцию как часть большего синтаксиса выражения (Обычно присваивание переменной). Функции , Определенные с помощью функций Выражения могут быть именованными или анонимными. Функция Выражения не должны начинаться с «функции» (отсюда круглые скобки Вокруг приведенного ниже примера самовывоза).

Присвоение переменной функции означает, что никакой Hoisting, как мы знаем, функции в JavaScript могут Hoist, означает, что их можно вызывать до того, как они будут объявлены, в то время как переменные должны быть объявлены до получения доступа к ним, поэтому в этом случае мы не можем доступ к функции до того, как она объявлена, также это может быть способ написания ваших функций, для функций, которые возвращают другую функцию, такое объявление может иметь смысл, также в ECMA6 и выше, вы можете назначить это функции стрелки, которая может использоваться для вызова анонимных функций, также этот способ объявления является лучшим способом создания функций конструктора в JavaScript.

2. Объявление функции

function functionTwo() {
    // Some code
}

Объявление функции определяет именованную переменную функции без , Требующей присваивания переменной. Объявления функций встречаются в виде Автономных конструкций и не могут быть вложены в нефункциональные блоки. Их можно рассматривать как братьев и сестер объявлений переменных. Так же, как объявления переменных должны начинаться с «Var», Function Объявления должны начинаться с «function».

Это нормальный способ вызова функции в JavaScript, эта функция может быть вызвана еще до того, как вы объявите ее, так как в JavaScript все функции получают Hoisted, но если вы используете 'строгий', это не будет Hoist, как ожидалось, это хороший способ вызывать все нормальные функции, которые не большие в строках и не являются функциями-конструкторами.

Кроме того, если вам нужна дополнительная информация о том, как работает подъем в JavaScript, перейдите по ссылке ниже:

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

7
Alireza

Это всего лишь два возможных способа объявления функций, а во-вторых, вы можете использовать функцию до объявления.

5
Tao

new Function() может использоваться для передачи тела функции в строку. И, следовательно, это может быть использовано для создания динамических функций. Также передача сценария без выполнения сценария.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()
4
SuperNova

Это называется выражением функции:

var getRectArea = function(width, height) {
    return width * height;
};

console.log("Area of Rectangle: " + getRectArea(3,4));
// This should return the following result in the console: 
// Area of Rectangle: 12

Это называется объявлением функции:

var w = 5;
var h = 6;

function RectArea(width, height) {  //declaring the function
  return area = width * height;
}                                   //note you do not need ; after }

RectArea(w,h);                      //calling or executing the function
console.log("Area of Rectangle: " + area);
// This should return the following result in the console: 
// Area of Rectangle: 30

Надеюсь, что это поможет объяснить, в чем разница между выражением функций и объявлением функций и как их использовать. Благодарю.

1
Kean Amaral

Выражение в JS : что-то, что возвращает значение 
Пример: попробуйте следующее в chrome console:

a = 10
output : 10

(1 + 3)
output = 4

Декларация/Заявление : То, что не возвращает значение 
Пример:

if (1 > 2) {
 // do something. 
}

здесь (1> 2) является выражением, а утверждение «если» - нет. Это ничего не возвращает. 


Точно так же у нас есть объявление функции/оператор против выражения функции 
Давайте рассмотрим пример:

// test.js

var a = 10;

// function expression
var fun_expression = function() {
   console.log("Running function Expression");
}

// funciton expression

function fun_declaration() {
   console.log("Running function Statement");
}

Важно: Что происходит, когда движки JavaScript запускают вышеуказанный файл js.

  • Когда этот js запустится, произойдут следующие вещи:

    1. В памяти будут созданы переменные 'a' и 'fun_expression'. И память будет создана для выражения функции 'fun_declaration'
    2. «а» будет присвоен «неопределенный». 'fun_expression' будет присвоено значение 'undefined'. 'fun_declaration' будет в памяти полностью. 
      Примечание. Вышеуказанные шаги 1 и 2 называются «контекст выполнения - фаза создания»

Теперь предположим, что мы обновили JS до.

// test.js

console.log(a)  //output: udefined (No error)
console.log(fun_expression)  // output: undefined (No error)
console.log(fun_expression()) // output: Error. As we trying to invoke undefined. 
console.log(fun_declaration()) // output: running function statement  (As fun_declaration is already hoisted in the memory). 

var a = 10;

// function expression
var fun_expression = function() {
   console.log('Running function expression')
}

// function declaration

function fun_declaration() {
   console.log('running function declaration')
}

console.log(a)   // output: 10
console.log(fun_expression()) //output: Running function expression
console.log(fun_declaration()) //output: running function declaration

Вывод, упомянутый выше в комментариях, должен быть полезен для понимания различий между выражением функции и оператором/объявлением функции.

0
Santosh Pillai

Следует отметить один важный момент:

пусть есть две функции: -

sum(1,2);

const sum = function(first, second) {
  return first + second;
}

В приведенном выше случае это даст ошибку, что сумма не определена, но

sum(1,2);

function sum(first, second) {
  return first + second;
}

Эта функция не выдаст ошибку, так как в этом случае будет иметь место function hoisting.

0
Nitesh Ranjan

Именованные функции против анонимных функций

Выражения анонимных функций быстро и легко набираются, и многие библиотеки и инструменты поддерживают этот идиоматический стиль кода. Тем не менее, у них есть несколько недостатков для рассмотрения:

  1. У анонимных функций нет полезного имени для отображения в следах стека, что может усложнить отладку.
  2. Без имени, если функция должна ссылаться на себя, для рекурсии и т.д.
  3. Анонимные функции опускают имя, которое может вызвать менее читаемый код.

Имена функций именования

Предоставление имени для выражения вашей функции довольно эффективно устраняет все эти недостатки и не имеет ощутимых недостатков. Лучше всего всегда называть выражения вашей функции:

setTimeout(function timeHandler() { // <-- named function here!
  console.log('I've waited 1 second');
}, 1000);

Именование выражения немедленной вызванной функции (IIFE): 

var a = 42;

(function IIFE(global) { // <-- named IIFEs!
  console.log(global.a); // 42
})(window);

Примечание: для функций, назначенных переменной, наименование функции, в этом случае, не очень распространено и может вызвать путаницу, в этом случае лучше использовать функцию стрелки.

0
Shakespear

Я предпочитаю определять функцию как переменную:

let first = function(x){
   return x[0];
}

Вместо:

function first(){
    ....
}

Потому что я могу использовать выражения и декораторы при определении функции. Например:

let safe = function(f){
  try {f()...}
}
let last = safe(function(x){return x[0]}).

Также с ES6 намного короче:

 let last = x => x[0]
 ...........
 function last(x){
     return x[0];
 }
......

let last = safe(x => x[0]);
0
user2693928

Еще одно различие между обеими функциями заключается в том, что functionOne можно использовать как переменную, которая может содержать несколько функций, а functionTwo содержит некоторый блок кода, который выполняется все при вызове. Пожалуйста, проверьте ниже:

   var functionOne = (function() {
      return {

         sayHello: function(){
                console.log('say hello')

         },
         redirectPage:function(_url){
                window.location.href = _url;
         }

      }
})();

У вас есть выбор, какую функцию вызывать. например, functionOne.sayHello или functionOne. redirectPage. И если вы вызовете functionTwo, тогда будет выполнен весь блок кода.

0
H.Ostwal