В чем разница в стиле закрытия?

JavaScript: разница в стиле закрытия

В JavaScript есть два популярных стиля замыкания. Первый я называю анонимным конструктором:

new function() {
    var code...
}

и встроенная выполняемая функция:

(function() {
   var code...
})();

есть ли разница в поведении между этими двумя? Один «лучше» другого?

5 ответов

Различия в стилях закрытия - JavaScript

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

В основном поведение

new expression

Фактически эквивалентно

var tempObject = {};
var result = expression.call(tempObject);
if (result is not an object)
     result = tempObject;

Хотя, конечно, tempObject и result — это временные значения, которые вы никогда не увидите (это детали реализации в интерпретаторе), и не существует механизма JS для проверки «не является объектом».

В общем случае метод «new function() { .. }» будет медленнее из-за необходимости создания объекта this для конструктора.

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

одна вещь, которую я понял, что я упустил из виду, это то, что tempObject получит прототип выражения, например (до вызова выражения) tempObject.__proto__ = expression.prototype

первый тоже выполняется. Сравните его с именованным конструктором:

function Blah() {
     alert('blah');
}
new Bla();

это на самом деле тоже выполнение кода. То же самое касается и анонимного конструктора...

Но это был не вопрос ;-)

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

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

Также (function(){ ... })(); сделайте хорошие маркеры книжного конца, чтобы вы могли сразу увидеть, что вы входите и выходите из области замыкания. Это хорошо, потому что это предупреждает программиста, читающего его, об изменении области, и особенно полезно, если вы делаете некоторую постобработку файла, например, для минификации.

Ну, я сделал такую страницу:

<html>
<body>
<script type="text/javascript">
var a = new function() { 
  alert("method 1");

  return "test";
};

var b = (function() {
  alert("method 2");

  return "test";
})();

alert(a);  //a is a function
alert(b);  //b is a string containing "test"

</script>
</body>
</html>

Достаточно удивительно (по крайней мере для меня), что он оповестил и «метод 1», и метод 2. Я не ожидал, что «метод 1» будет оповещён. Разница была в значениях a и b. a — это сама функция, а b — строка, которую функция возвращала.

Да, между ними есть различия.

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

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

Пример:

<html>
<body>
<script type="text/javascript">

new function() { 
a = "Hello";
alert(a + " Inside Function");
};

alert(a + " Outside Function");

(function() { 
var b = "World";
alert(b + " Inside Function");
})();

alert(b + " Outside Function");
</script>
</body>
</html>

В приведенном выше коде вывод будет примерно таким:

Hello Inside Function
Hello Outside Function
World Inside Function

... затем вы получите ошибку, так как «b» не определено вне функции!

Поэтому я считаю, что второй способ лучше... безопаснее!

Это связано с тем, что перед «a» опущено «var», что делает его глобальным и не имеет отношения к вопросу.

Получение текста из выпадающего списка

Получение текста из выпадающего списка

Это возвращает значение того, что выбрано в моем выпадающем меню. document.getElementById('newSkill').value Однако я не могу найти, какое свойство использовать для текста, который в данный момент отображается в раскрывающемся меню. Я попробовал "text", но это не дало ответа, кто-нибудь здесь знает? Для тех, кто не уверен, вот HTML-код раскрывающегося списка. <select name="newSkill" id="newSkill"> <option value="1">A skill</option> <option value="2">Another skill</option> <option value="3">Yet another skill</option> </select> На основе вашего примера HTML-кода вот один из способов получить отображаемый текст выбранного в данный момент параметра: var skillsSelect = document.getElementById("newSkill"); var selectedText = skillsSelect.options[skillsSelect.selectedIndex].text; Для тех, кто…

Подробнее »

JavaScript должен запускаться при отображении ModalPopupExtender

Выполнение Javascript при отображении ModalPopupExtender

ASP _ NET AJAX ModalPopupExtender имеет свойства OnCancelScript и OnOkScript, но, похоже, не имеет свойства OnShowScript. Я хотел бы указать функцию javascript для запуска каждый раз, когда отображается всплывающее окно. В прошлых ситуациях я устанавливал фиктивный элемент управления TargetControlID и предоставлял свой собственный элемент управления, который сначала выполняет некоторый код JS, а затем использует методы JS для отображения всплывающего окна. Но в этом случае я показываю всплывающее окно как из клиентского, так и из серверного кода. Кто-нибудь знает, как это сделать? Кстати, мне это было нужно, потому что у меня есть…

Подробнее »

Длина объекта JavaScript

Длина объекта JavaScript

У меня есть объект JavaScript. Есть ли встроенный или общепринятый способ получить длину этого объекта? const myObject = new Object(); myObject["firstname"] = "Gareth"; myObject["lastname"] = "Simpson"; myObject["age"] = 21; Это отчасти правда, но так много людей привыкли к «ассоциативному массиву» PHP, что они могут предположить, что это означает «упорядоченную ассоциативную карту», хотя объекты JS на самом деле…

Подробнее »