javascript - type - js function without function




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

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

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

}

или же

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

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

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

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

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

Двумя способами являются:

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

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


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

Термины:

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

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

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

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

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

  • Выражение функции Arrow (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
}

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

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

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

  1. Если в свободном режиме не в веб-браузере, движок 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)

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

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

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 .

Выражение функции Arrow (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. У них их нет. Вместо этого они закрывают контекст, в котором они определены. (Они также закрывают 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));

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

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

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

var o = {
    foo() {
    }
};

эквивалент в ES5 и ранее был бы:

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

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


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

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

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

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

Дополнительная информация

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

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

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

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

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

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

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


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

С

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

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

В то время как

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

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


Разница в том, что 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 действие не действует, в этом случае оно просто вызывает ошибку.


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

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

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


дает пример, где он называет назначенную функцию, чтобы иметь возможность использовать ее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." );

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

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

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

Variable

Javascript называется свободно типизированным языком. Это означает, что переменные Javascript могут хранить значение любого типа Data-Type . 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 », значение «default» по умолчанию объявлено «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

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

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

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

Chrome 62.0.3202

FireFox 55

Chrome Canary 63.0.3225


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


Firefox Chrome Canary Chrome


В свете аргументов «названные функции отображаются в стеках» современные механизмы 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

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

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.


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

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

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.


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

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

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

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

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

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

function functionTwo() {
    // Some code
}

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

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

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

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


Первая (функция 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) определяет синтаксис как
функцию Identifier opt (FormalParameterList opt ) {FunctionBody}


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

function abc(){}

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

var abc = function() {};

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

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

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

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

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


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

  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=superseeds 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. (функция) .name

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

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 может быть несколько разметок компиляции Microsecond JIST, но в конечном итоге результат будет таким же. Чтобы убедиться в этом, давайте рассмотрим эффективность JSPerf в microbenchmarks, сравнив скорость двух фрагментов кода. В тестах JSPerf найдены здесь . И здесь найдены тесты jsben.ch . Как вы можете видеть, есть заметная разница, когда их не должно быть. Если вы действительно такой урод, как я, то это может стоить больше, пытаясь уменьшить количество переменных и функций в области действия и особенно устранять полиморфизм (например, использовать одну и ту же переменную для хранения двух разных типов).

Что такое «ближайший блок»

«Ближайший блок» - ближайшая «функция» (включая асинхронные функции, функции генератора и асинхронные функции генератора). Однако интересно, что a function functionName() {}ведет себя как a, 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;
    }
}

  • Функция Arrow с 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;
    }
})();


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


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

  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
    

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

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

    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()}
    

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

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





idioms