Подтвердить что ты не робот

JavaScript: встроенные функции против предопределенных функций

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

Т.е. что лучше:

(function() {
  setTimeout(function() { /*some code here*/ }, 5);
})();

против

(function() {
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();


Странный вопрос, но мы почти ссоримся в команде по этому поводу.

4b9b3361

Ответ 1

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

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

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

setTimeout(function doSomethingLater() { alert('In a named function.'); }, 5);

и это использует оператор функции:

function doSomethingLater() { alert('In a named function.'); }
setTimeout(doSomethingLater, 5);

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

Если имя указано (текст после "функции", но перед скобкой), то это именованная функция независимо от того, является ли она встроенной или объявлена ​​отдельно. Если имя не указано, оно "анонимно".

Примечание: T.J. указывает, что IE mishandles назвал функциональные выражения нетривиальным способом (см. http://kangax.github.com/nfe/#jscript-bugs), и это важно отметить, я просто пытаясь сказать о терминологии.

Что вы должны использовать?

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

Утечка памяти

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

(function outerFunction() {
    var A = 'some variable';

   doStuff();
})();

В приведенном выше коде, когда "externalFunction" заканчивается "A" выходит за пределы области видимости и может быть собрано мусором, освобождая эту память.

Что делать, если мы добавим туда функцию?

(function outerFunction() {
    var A = 'some variable';

   setTimeout(function(){ alert('I have access to A whether I use it or not'); }, 5);
})();

В этом коде (выше) выражение функции, которое мы передаем setTimeout, имеет ссылку на "A" (через магию закрытия), и даже после завершения "внешней функции" "A" останется в памяти до тех пор, пока таймаут запускается, и функция разыменовывается.

Что делать, если мы передаем эту функцию чему-то, кроме setTimeout?

(function outerFunction() {
    var A = 'some variable';

   doStuff(function(){ alert('I have access to A whether I use it or not'); });
})();

function doStuff(fn) {
    someElement.onclick = fn;
}

Теперь выражение функции, которое мы передаем в "doStuff" , имеет доступ к "A" , и даже после завершения "внешней функции" "A" останется в памяти до тех пор, пока есть ссылка на переданную нами функцию в doStuff. В этом случае мы создаем ссылку на эту функцию (как обработчик события), и поэтому "A" останется в памяти до тех пор, пока этот обработчик события не будет очищен. (например, кто-то звонит someElement.onclick = null)

Теперь посмотрим, что произойдет, когда мы используем оператор функции:

(function outerFunction() {
    var A = 'some variable';

    function myFunction() { alert('I have also have access to A'); };
    doStuff(myFunction);
})();

Та же проблема! "myFunction" будет очищен только в том случае, если "doStuff" не содержит ссылки на него, и "A" будет очищен только при очистке "myFunction". Неважно, использовали ли мы выражение или выражение; имеет значение, если ссылка на эту функцию создается в "doStuff" !

Ответ 2

Существует одно существенное различие между двумя: последнее имеет имя.

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

(function(){
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();

... форма вообще. Однако правила должны быть сломаны, но не рабски поклонились.: -)

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

(function(){
  setTimeout(function invokeMe(){ /*some code here*/ }, 5);
})();

Проблема заключается в том, что каждая версия интерпретатора JavaScript из Microsoft ( "JScript" ), включая (в удивительной) версии IE9, неправильно обрабатывает это именованное выражение функции и создает два полностью различные функции в разное время. (Доказательство, попробуйте его в IE9 или более ранней версии, а также в любом другом браузере.) IE делает это неправильно двумя способами: 1. Создает два отдельных функциональных объекта и 2. Вследствие одного из них он "пропускает" символ имени в охватывающую область выражения (в явном нарушении Раздел 13 спецификации). Подробности здесь: Double take

Ответ 3

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

Я лично использую выражения функций (первый путь) для обработчиков setTimeout.

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

Ответ 4

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

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

Любой аргумент против любого стиля является чистым bikeshedding, imo.

Ответ 5

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

(function(){
  function invokeMe() {
    if(..) setTimeout(invokeMe, 5);
  }
  setTimeout(invokeMe, 5);
})();

Ответ 6

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

Ответ 7

Разве мы не можем просто ладить?

(function(){
  setTimeout( (function InvokeMe(){ /*some code here*/ }), 5);
})();

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

Ответ 8

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

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

//an example where you wold prefer to use an anonymous function.
//you can assign this (anonymous) function to a variable, so you get your "name" back.
function someFn(){
    if(condition){
        //the variable declaration has been hoisted, 
        //but the function is created at this point, and only if necessary.
        var process = function(value){/* */};
        switch(condition2){
            case 1: process(valueFor1); break;
            case 2: process(valueFor2); break;
            /* ... */
        }
    }
}

function someFn(){
    var process;
    if(condition){
        process = function(value){ /* A */ }
    }else{
        process = function(value){ /* B */ }
    }

    //beware, depending on your code, "process" may be undefined or not a function
    process(someValue);
}


//an example where you would prefer (/ utilize) the hoisting.
function someFn(){
    /* some code */
    while(condition){
        //some might want to keep the function definition near the code where it is used,
        //but unlike an anonymous function or a lambda-expression this process-function 
        //is created only once per function-call, not once per iteration.
        function process(value, index){ /* ... */ }
        /* ... */
        process(value, index)
    }
}

поэтому, как правило:

  • внутри цикла не должно быть анонимной функции или лямбда-выражения

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

  • Если вы знаете свой бизнес (JavaScript), вы знаете, когда игнорировать этот совет

Ответ 9

Предопределенные именованные функции могут уменьшить проблему обратного вызова JavaScript, которая упоминается в http://callbackhell.com/

Ответ 10

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

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

Пример:

setTimeout(function() { // I need to scroll to see the other arguments

  // many lines of code

}, 0); // <- where does this '0' belong to?

Ответ 11

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

Ответ 12

Я предпочитаю использовать именованные функции. Именованные функции отображаются по имени на всех отладчиках (воздух, firebug, IE).

Пример:

Обратите внимание, что вы также можете иметь встроенные именованные функции, такие как

{
    method: function obj_method(){}
}

Таким образом, когда вы смотрите на трассировку стека, вы увидите функцию obj_method вместо анонимного.

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

Ответ 13

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

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

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

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

Именованные функции также абсолютно необходимы, если вы когда-либо попадаете в Test Driven Development.