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

Что происходит с `return function()` в javascript анонимных функциях в настоящее время? (ЛУЧШИЕ ПРАКТИКИ)

ПРИМЕЧАНИЕ. Обновлено и перезаписано

Этот вопрос был переделан и обновлен. Пожалуйста, извините устаревшие ссылки ниже. Спасибо.

В последнее время я видел много javascript-кода, что выглядит неправильно для меня. Что я должен предлагать в качестве лучшей схемы кода в этой ситуации? Я воспроизведу код, который я видел, и краткое описание для каждого из них:

Блок кода # 1

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

$(document).ready( function() { 
  return function() { 
    /* NOPs */
  }
});

Кодовый блок # 2

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

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

$(document).ready( (function() { 
  return function() { 
    /* NOPs */
  }
}));

Блок кода # 3

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

$(document).ready( function() { 
  (return function() { 
    /* NOPs */
  })()
}); 

Блок кода # 4

примерный кодовый блок

$('#mySelector').click( function(event) { 
  alert( $(this).attr('id') );

  return function() { 
    // before you run it, what the value here?
    alert( $(this).attr('id') );
  }
});

Комментарий:

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

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


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

$(document).ready(function() {
 $('body').click((function(){
  return function()
  {
   if (counter == null) {
    var counter = 1;
   }
   if(counter == 3) {
     $(this).css("background-image","url(3.jpg)");
     $(this).css("background-position","10% 35%");
     var counter = null;
   }
   if(counter == 2) {
     $(this).css("background-image","url(2.jpg)");
     $(this).css("background-position","10% 35%");
     var counter = 3;
   }
   if(counter == 1) {
     $(this).css("background-image","url(1.jpg)");
     $(this).css("background-position","40% 35%");
     var counter = 2;
   }


  }
 })());
});

Вот как я предложил переписать свой код:

var counter = 1;
$(document).ready(function() {
    $('body').click(function() {
        if (counter == null) {
            counter = 1;
        }
        if (counter == 3) {
            $(this).css("background-image", "url(3.jpg)");
            $(this).css("background-position", "10% 35%");
            counter = 1;
        }
        if (counter == 2) {
            $(this).css("background-image", "url(2.jpg)");
            $(this).css("background-position", "10% 35%");
            counter = 3;
        }
        if (counter == 1) {
            $(this).css("background-image", "url(1.jpg)");
            $(this).css("background-position", "40% 35%");
            counter = 2;
        }
    });
});

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

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

4b9b3361

Ответ 1

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

Функция самозапуска принимает шаблон (function f () { /* do stuff */ }()) и оценивается немедленно, а не при его вызове. Так что-то вроде этого:

var checkReady = (function () {
    var ready = false;
    return {
        loaded: function () { ready = true; },
        test: function () { return ready; }
    };
}())
$(document).ready(checkReady.loaded);

создает замыкание, связывающее объект, возвращаемый как checkready с переменной ready (которая скрыта от всего, что находится за пределами закрытия). Это позволит вам проверить, загружен ли документ (в соответствии с jQuery), вызвав checkReady.test(). Это очень мощный шаблон и имеет множество законных целей (namespacing, memoization, metaprogramming), но на самом деле это не обязательно в вашем примере.

EDIT: Арг, я неправильно понял ваш вопрос. Не понимал, что вы вызываете плохие практики, а не просите разъяснений по шаблонам. Более подробно об окончательной форме, о которой вы спрашивали:

(function () { /* woohoo */ }())
(function () { /* woohoo */ })()
function () { /* woohoo */ }()

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

Ответ 2

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

Тем не менее, иногда вам это нужно.

(function(){
    var x = 'test';
    alert(x);
})()

alert(typeof(x)); //undefined

Здесь переменная x заблокирована в области функций.

(я нашел приведенный выше пример в http://helephant.com/2008/08/javascript-anonymous-functions/)

Итак, вы можете делать странные вещи с областью видимости с помощью javascript; это один из способов. Я согласен с вашими чувствами в том, что много js-кода сложнее, чем должно быть.

Ответ 3

Анонимные функции полезны для:

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

Подробнее об этих темах читайте по следующей ссылке: анонимные функции javascript

Ответ 4

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

// I picked document ready from jQuery cos you ALL know it, I'm sure ;) 
$('#mySelector').click( function(event) { // this line is all boilerplate, right? 
  alert( $(this).attr('id') ); 

  return function() { // <-- WHAT THE ???? IS THIS ????  ? 
    // before you run it, what the value here? 
    alert( $(this).attr('id') ); 
  } 
}); 

а также ваш первый пример, возвращаемая функция анонов никогда не запускается. если вместо функции вы возвращаете false, действие по умолчанию будет предотвращено. как я полагаю, он получает в браузере event handler returned truish.

если он был изменен на этот

// I picked document ready from jQuery cos you ALL know it, I'm sure ;) 
$('#mySelector').click( function(event) { // this line is all boilerplate, right? 
  alert( $(this).attr('id') ); 

  return function() { // <-- WHAT THE ???? IS THIS ????  ? 
    // before you run it, what the value here? 
    alert( $(this).attr('id') ); 
  } 
}() ); 

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

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

Ответ 5

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

$(document).ready(function() {
    for (var i = 9; i <= 10; i++) {
        $('#button'+i).click(function() {
            alert('Button '+i+' clicked');
        });
    }
});

это будет предупреждать кнопку "10 нажата" для всех кнопок, но эта будет работать правильно:

$(document).ready(function() {
    for (var i = 9; i <= 10; i++) {
        (function() {
            var j = i;
            $('#button'+j).click(function() {
                alert('Button '+j+' clicked');
            });
        })();
    }
});

Ответ 6

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

Примеры/пояснения см. в разделе

Ответ 7

Для блока кода один, который немного похож на шаблон, который я видел для объектов с частными членами. Рассмотрим:

function MyObject()  {
   var privateMember = 1;

   return {
        "Add":function(x) {return x + privateMember;},
        "SetPrivateMember":function(x) {privateMember = x;},
        "GetPrivateMember":privateMember
   };
}