var functionName = function () {} vs functionName () {}

avatar
Richard Garside
3 декабря 2008 в 11:31
1098695
41
7241

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

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

Два способа:

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

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

Источник

Ответы (41)

avatar
Greg
3 декабря 2008 в 11:37
5326

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

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

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

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

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

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

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

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

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError
supercat
26 октября 2020 в 21:37
0

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

rails_has_elegance
4 декабря 2020 в 19:19
4

Предложение «из-за подъема» может создать неверное впечатление, что поднимается только названная функция. Фактически, как var functionOne, так и function functionTwo в какой-то степени поднимаются - просто для функции functionOne установлено значение undefined (вы можете назвать это полуподъемом, переменные всегда поднимаются только до этой степени), тогда как function functionTwo полностью поднял в том, что он определен и объявлен. Вызов чего-то неопределенного, конечно же, вызовет ошибку typeError.

R. Hoek
27 января 2021 в 08:05
1

Спасибо Грегу и @Ben_Aston за объяснение разницы. Но мог бы кто-нибудь из вас также пролить свет на «за» и «против», когда спрашивает пользователь?

avatar
S.G
21 октября 2021 в 12:33
0

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

var add=function(a, b){
  return a + b;
}
avatar
root
31 июля 2021 в 14:26
0

Во время точки останова в отладчике / DevTools, если вы используете формат function functionName() {} в консоли, вы не можете впоследствии использовать functionName() в консоли (он говорит «не определен»), тогда как после var functionName = function() {} , вы можете использовать эту функцию.

См. Этот вопрос.

avatar
GalaxyCat105
8 сентября 2020 в 21:39
0

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

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

function x() {
  console.log(this)
}.bind('string')

x()

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

var x = function() {
  console.log(this)
}.bind('string')

x()
avatar
Robin Hossain
3 марта 2020 в 08:43
0

var functionOne = function() {} определяется во время выполнения, а function functionTwo() {} определяется во время синтаксического анализа.

// Run-Time function declaration 
functionOne(); // Calling functionOne function here will give an Error
var functionOne = function () {
  // Some code
};

// Parse-Time function declaration 
functionTwo(); // Calling functionTwo function will not give an Error
function functionTwo() {
  // Some code...
}

Объяснение между временем выполнения и временем анализа время выполнения javascript и время синтаксического анализа

avatar
Willem van der Veen
20 июня 2019 в 10:06
1

Объявление разностной функции и выражение функции:

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

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

  1. Выражения функций могут быть анонимными, тогда как объявление функции должно иметь имя.
  2. Оба имеют свойство имени, которое используется для идентификации функции. Свойство name выражения функции - это имя переменной, к которой оно привязано, тогда как имя объявления функции - это просто заданное имя.
  3. Объявления функций поднимаются, а выражения функций - нет. Поднимается только переменная со значением undefined.

Вот пример:

try {
  functionOne();
} catch (e) {
  console.log('i cant run because im not hoisted');
}

functionTwo();

// function expression, does not get hoisted
let functionOne = function randomName() {
    // Some code
};

// function declaration, gets hoisted
function functionTwo() {
   console.log('I get hoisted');
}

try {
  randomName(); // this isn't the proper name, it is functionOne
} catch (e) {
  console.log('You cant call me with randomName my name is function one');
}

:

avatar
H.Ostwal
2 января 2019 в 06:50
0

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

   var functionOne = (function() {
      return {

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

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

      }
})();

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

avatar
Shakespear
17 декабря 2018 в 16:58
5

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

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

В то время как второй - Объявление функции :

function functionTwo () {
  // some code
}

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

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

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

  • Читаемость: анонимные функции пропускают имя, что может привести к ухудшению читаемости кода.

  • Отладка: анонимные функции не имеют имени в трассировке стека, что может затруднить отладку.

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

Выражение функции именования

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

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

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

(function IIFE(str) { // <-- look, always name IIFEs!
  console.log(str); // "Hello!"
})('Hello!');

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

avatar
Nitesh Ranjan
18 октября 2018 в 18:57
1

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

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

sum(1,2);

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

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

sum(1,2);

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

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

avatar
Kean Amaral
14 июля 2018 в 22:56
4

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

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

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

avatar
Santosh Pillai
15 мая 2018 в 00:22
1

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

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. 'a' будет присвоено 'undefined'. '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

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

avatar
user2693928
8 марта 2018 в 11:49
1

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

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]);
avatar
Jack Giffin
15 января 2018 в 01:55
35

???????????????????? ???????????? ???????????????? ??????????????????????????????????????? ??????????????????????????????????????????? ???????????????????????????? ???????????? ???????????? ??????????????????????????????????? ?????????????????????????????????????????????? ???????? ??????????????????????????????????? ???????? ???????????????????????? ????????????????????.

  1. Доступность (объем) функции

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

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

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;
}

Приведенный выше код по функциональности идентичен приведенному ниже коду. Обратите внимание, что явное присвоение add = undefined излишне, потому что простое выполнение var add; в точности совпадает с var add=undefined.

var add = undefined;

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

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

Следующее не работает, потому что var add= начинает выражение и делает следующее function 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;
}
  1. (функция) .name

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

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

В противном случае, если функция объявлена ​​как 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, <18412512> )

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;
    }
})();
avatar
Panos Kal.
28 сентября 2017 в 04:34
12

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

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

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

Хром 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 named_anonymous

Ronny Sherer
14 октября 2020 в 12:59
0

Различия в результатах слишком малы, чтобы их можно было рассматривать как разницу. Если вы запустите тест 100 раз, вы получите 100 результатов.

Panos Kal.
14 октября 2020 в 14:44
0

@RonnySherer, вы знакомы с jsperf? Тесты проводились после более чем 10 миллионов запусков!

Ronny Sherer
17 октября 2020 в 21:30
0

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

Panos Kal.
18 октября 2020 в 13:09
0

@RonnySherer js perf создает виртуальную среду специально для учета процессов с этими небольшими различиями. Он не запущен на моем компьютере. Работает только это. Когда что-то такое маленькое, может быть, кому-то наплевать. НО тем не менее я считаю это правильно и сообщаю об этом. Если кто-то хочет использовать его внутри цикла с миллиардами итераций, ему следует выбрать функцию с наилучшей производительностью.

Ronny Sherer
21 октября 2020 в 14:54
0

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

avatar
Alireza
9 мая 2017 в 13:56
9

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

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

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

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

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

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

function functionTwo() {
    // Some code
}

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

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

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

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

avatar
Anoop Rai
14 августа 2016 в 09:13
11

В 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 () {} vs function fn () {}

avatar
SuperNova
10 мая 2016 в 07:05
6

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

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

secondFunction()
Jack Giffin
10 мая 2018 в 21:06
0

Хотя это хорошо и верно, но какое именно это имеет отношение к задаваемому вопросу?

avatar
Yash
25 января 2016 в 14:46
60

Hoisting - это действие интерпретатора 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, переменная декларация значения по умолчанию также «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'
    };

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

(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

avatar
Nitin9791
28 декабря 2015 в 20:18
11

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

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

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

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

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

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

functionOne();
function functionOne() {
   // Some code
}
avatar
varna
9 сентября 2015 в 10:30
17

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

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

    var today = function today() {return new Date()}
    
avatar
Rohan
21 июля 2015 в 07:45
28

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

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

var foo = function foo() {};

Описание функции:

function foo() {};

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

Итак

function foo() {};

заменяется на

var foo = function foo() {};

который расширяется до:

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

И они оба поднялись наверх кода.

Screenshot from video

avatar
Tao
24 июня 2015 в 10:08
8

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

avatar
Leon Gaban
1 мая 2015 в 15:06
47

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

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

enter image description here

Объявления функций быстрее, и это действительно важно в веб-разработке, верно? ;)

d9k
1 марта 2021 в 17:19
0

см. ответ о производительности ниже, разные результаты

avatar
Jackson
12 октября 2014 в 00:58
12

В свете аргумента «именованные функции отображаются в трассировке стека» современные движки 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:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


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


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


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


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


func.name: l
Trace:
l@http://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:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://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)

Нитро

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

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

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

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

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

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

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

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

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

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

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

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
avatar
suhailvs
9 августа 2014 в 02:45
115

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

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();
                            ---------------
avatar
sla55er
5 июня 2014 в 08:28
36

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

function abc(){}

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

var abc = function() {};

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

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

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

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

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

avatar
T.J. Crowder
4 марта 2014 в 13:35
687

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

Условия:

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

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

  • «Анонимный» 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, если вы помещаете объявление функции внутри структуры управления, например if, switch, while и т. Д., Например:

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

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

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

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

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

Правила для свободных режимов сложны, но в режиме strict объявления функций в блоках просты: они локальны для блока (они имеют область видимости блока , которая также новинка в 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)

«Анонимный» function Выражение

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

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

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

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

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

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

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

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

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

Обратите внимание, что NFE часто были источником ошибок для реализаций JavaScript. IE8 и более ранние версии, например, обрабатывают NFE совершенно неправильно, создавая две разные функции в два разных момента. В ранних версиях 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 выше является одной из их форм. Если у вас есть несколько аргументов для передачи функции, используйте скобки:

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));

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

Объявление метода в инициализаторе объекта (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.

avatar
Pawel Furmaniak
25 октября 2013 в 16:38
15

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

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
avatar
Mbengue Assane
29 марта 2013 в 13:26
82

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

С

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

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

Хотя

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

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

avatar
eljenso
6 февраля 2013 в 16:29
38

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

Однако есть разница в , как и , когда объект функции фактически связан со своей переменной. Это различие связано с механизмом, называемым подъемом переменных в 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.

avatar
NullPoiиteя
5 января 2013 в 18:37
17

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

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

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

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

function foo() {
    return 3;
}

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

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

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

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

// 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 (FormalParameterList opt ) {FunctionBody}

avatar
Herc
29 ноября 2012 в 11:28
28

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

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

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

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

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

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

avatar
Ingo Kegel
15 октября 2012 в 10:42
18

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

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.

avatar
Joel Purra
4 августа 2012 в 15:24
20

@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." );
avatar
Sean McMillan
3 марта 2011 в 19:19
98

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

Я часто создаю модули JavaScript по такой схеме:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

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

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

avatar
Rob
8 августа 2010 в 19:44
67

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

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

}

или

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

Существует множество методов размещения имен. Это стало еще более важным с появлением множества доступных модулей JavaScript.

См. Также Как объявить пространство имен в JavaScript?

avatar
Christian C. Salvadó
8 августа 2010 в 19:32
160

Говоря о глобальном контексте, оба оператора 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'

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

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

 function test () {}
 test = null;

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

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

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

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

Необходимо прочитать:

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

avatar
thomasrutter
20 апреля 2010 в 04:54
136

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

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

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

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

Дополнительная техническая информация

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

  1. Ваш первый фрагмент кода показывает выражение функции . Это включает использование оператора «функции» для создания функции - результат этого оператора может быть сохранен в любой переменной или свойстве объекта. Таким образом, выражение функции является мощным. Выражение функции часто называют «анонимной функцией», потому что у него не обязательно должно быть имя,
  2. Ваш второй пример - это объявление функции . При этом используется оператор «функция» для создания функции. Функция становится доступной во время синтаксического анализа и может быть вызвана в любом месте этой области. Вы можете сохранить его в свойстве переменной или объекта позже.
  3. Третий способ определения функции - это конструктор «Function ()» , который не показан в вашем исходном сообщении. Не рекомендуется использовать его, поскольку он работает так же, как eval(), у которого есть свои проблемы.
avatar
Sasha Firsov
23 января 2010 в 20:32
34

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

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

Я подозреваю, что последуют другие ПРОФИ для названных функций. А то, что указано как преимущество именованных функций, является недостатком для анонимных.

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

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
avatar
Kafka
18 декабря 2008 в 19:30
29

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

Дополнительные сведения об анонимных функциях и лямбда-исчислении можно найти в Википедии: Анонимные функции.

avatar
Eugene Lazutkin
3 декабря 2008 в 17:43
2019

Сначала я хочу исправить Грега: 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"

Одной из веских причин для использования комбинированного стиля является атрибут «name» объектов функции ( не поддерживается 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() - ответ: это зависит от браузера.

lfx_cool
3 апреля 2021 в 16:27
0

var abc = function () {}; console.log (abc.name); // "abc" // с 2021 г.

Eugene Lazutkin
15 апреля 2021 в 01:17
1

Судя по всему, среда выполнения JS стала умнее. А пока заверните его и: var abc = (() => function () {}) (); console.log (abc.name); // ничего такого