В последнее время я много читал Javascript и заметил, что весь файл упакован, как показано ниже, в импортируемые файлы .js.
(function() {
...
code
...
})();
В чем причина этого, а не простой набор функций конструктора?
javascript
scope
coding-style
iife
Эндрю Коу
источник
источник
Ответы:
Обычно это пространство имен (см. Далее) и управление видимостью функций-членов и / или переменных. Думайте об этом как об определении объекта. Техническое название для него - выражение немедленного вызова функции (IIFE). Плагины jQuery обычно пишутся так.
В Javascript вы можете вкладывать функции. Итак, законно следующее:
Теперь вы можете звонить
outerFunction()
, но видимостьinnerFunction()
ограничена рамкамиouterFunction()
, то есть частнойouterFunction()
. Он в основном следует тому же принципу, что и переменные в Javascript:Соответственно:
В приведенном выше сценарии вы можете звонить
globalFunction()
откуда угодно, но не можете звонитьlocalFunction1
илиlocalFunction2
.Когда вы пишете
(function() { ... })()
, вы делаете код внутри первого набора скобок литералом функции (т.е. весь «объект» на самом деле является функцией). После этого вы вызываете функцию (финал()
), которую вы только что определили. Итак, основное преимущество этого, как я уже упоминал ранее, заключается в том, что вы можете иметь частные методы / функции и свойства:В первом примере вы явно вызываете
globalFunction
по имени для его запуска. То есть вы бы простоglobalFunction()
запустили его. Но в приведенном выше примере вы не просто определяете функцию; Вы определяете и вызываете это за один раз. Это означает, что когда ваш файл JavaScript загружен, он сразу же исполняется. Конечно, вы можете сделать:Поведение во многом будет таким же, за исключением одного существенного различия: вы избегаете загрязнения глобальной области при использовании IIFE (как следствие, это также означает, что вы не можете вызывать функцию несколько раз, так как у нее нет имени, но так как эта функция должна выполняться только тогда, когда она действительно не является проблемой).
Отличная вещь с IIFE заключается в том, что вы также можете определять вещи внутри и выставлять только те части, которые вы хотите, внешнему миру (пример пространства имен, так что вы можете создать свою собственную библиотеку / плагин):
Теперь вы можете позвонить
myPlugin.public_function1()
, но вы не можете получить доступprivate_function()
! Очень похоже на определение класса. Чтобы лучше это понять, я рекомендую следующие ссылки для дальнейшего чтения:РЕДАКТИРОВАТЬ
Я забыл упомянуть. В этом финале
()
вы можете передать все, что хотите внутри. Например, когда вы создаете плагины jQuery, вы передаетеjQuery
или$
вот так:Итак, что вы делаете здесь - это определение функции, которая принимает один параметр (вызываемый
jQ
, локальная переменная и известный только этой функции). Затем вы вызываете функцию самостоятельно и передаете параметр (также вызываемыйjQuery
, но этот - из внешнего мира и является ссылкой на сам jQuery). В этом нет необходимости, но есть некоторые преимущества:Ранее я описывал, как эти функции запускаются автоматически при запуске, но если они запускаются автоматически, кто передает аргументы? Этот метод предполагает, что все необходимые параметры уже определены как глобальные переменные. Так что, если бы jQuery еще не был определен как глобальная переменная, этот пример не работал бы. Как вы можете догадаться, во время своей инициализации jquery.js определяет глобальную переменную 'jQuery', а также ее более известную глобальную переменную '$', которая позволяет этому коду работать после включения jQuery.
источник
;(function(jQ) { ... code ... })(jQuery);
таким образом, если кто-то пропустил точку с запятой в своем сценарии, это не сломало бы ваш, особенно если вы планируете минимизировать и объединить свой сценарий с другим.(function (context) { ..... })(this)
что затем позволит вам присоединить все, что вам нравится, к родительскому контексту, тем самым раскрывая его.Короче говоря
Резюме
В своей простейшей форме этот метод стремится заключить код в область действия функции .
Это помогает уменьшить шансы на:
Она не определяет , когда документ будет готов - это не какое - то
document.onload
ниwindow.onload
Это обычно известно как
Immediately Invoked Function Expression (IIFE)
илиSelf Executing Anonymous Function
.Код объяснил
В приведенном выше примере любая переменная, определенная в функции (т.
var
Е. Объявленная с использованием ), будет «закрытой» и будет доступна ТОЛЬКО в области действия функции (как говорит Вивин Палиат). Другими словами, эти переменные не видны / недоступны вне функции. Смотрите живую демонстрацию .Javascript имеет функцию определения области видимости. «Параметры и переменные, определенные в функции, не видны вне функции, и что переменная, определенная где-либо внутри функции, видна везде внутри функции». (из "Javascript: хорошие части").
Подробнее
Альтернативный код
В конце код, размещенный ранее, также можно сделать следующим образом:
Смотрите живую демонстрацию .
Корни
Итерация 1
Однажды кто-то, вероятно, подумал: «Должен быть способ избежать именования« myMainFunction », поскольку все, что нам нужно, - это выполнить его немедленно».
Если вы вернетесь к основам, вы обнаружите, что:
expression
: что-то, оценивающее значение. т.е.3+11/x
statement
: строка (и) кода, делающая что-то, НО это не оценивает к значению. т.е.if(){}
Аналогично, функциональные выражения оцениваются как значения. И одно из следствий (я полагаю?) Заключается в том, что они могут быть немедленно вызваны:
Таким образом, наш более сложный пример становится:
Посмотреть демо .
Итерация 2
Следующим шагом является мысль «почему есть
var myMainFunction =
если мы даже не используем это !?».Ответ прост: попробуйте удалить это, например, ниже:
Посмотреть демо .
Это не будет работать, потому что «объявления функций не могут быть вызваны» .
Хитрость заключается в том, что путем удаления
var myMainFunction =
мы преобразовали выражение функции в объявлении функции . Смотрите ссылки в разделе «Ресурсы» для более подробной информации об этом.Следующий вопрос: «Почему я не могу сохранить это как выражение функции с чем-то другим
var myMainFunction =
?Ответ: «Вы можете», и на самом деле есть много способов сделать это: добавив a
+
, a!
, a-
или, возможно, заключив в скобки пару (как это теперь делается по соглашению), и многое другое, я верю. Как пример:или
или
Поэтому, когда соответствующая модификация добавлена к тому, что когда-то было нашим «Альтернативным кодом», мы возвращаемся к тому же коду, который использовался в примере «Код объяснен»
Узнайте больше о
Expressions vs Statements
:Демистифицирующие Прицелы
Одна вещь, которая может задаться вопросом: «что происходит, когда вы НЕ определяете переменную« должным образом »внутри функции - т.е. вместо этого делаете простое присваивание?»
Смотрите живую демонстрацию .
По сути, если переменной, которая не была объявлена в ее текущей области действия, присваивается значение, то «выполняется поиск цепочки области действия до тех пор, пока она не найдет переменную или не достигнет глобальной области (в которой она будет создана).
В среде браузера (по сравнению с серверной средой, такой как nodejs) глобальная область определяется
window
объектом. Следовательно, мы можем сделатьwindow.myOtherFunction()
.Мой совет «Хорошей практики» по этой теме - всегда использовать
var
при определении чего-либо : будь то число, объект или функция и даже в глобальной области видимости. Это делает код намного проще.Замечания:
block scope
(Обновление: локальные переменные области видимости добавлены в ES6 .)function scope
&global scope
(window
область видимости в среде браузера)Узнайте больше о
Javascript Scopes
:Ресурсы
Следующие шаги
Как только вы получите эту
IIFE
концепцию, она приведет к томуmodule pattern
, что обычно делается путем использования этого шаблона IIFE. Радоваться, веселиться :)источник
Javascript в браузере действительно имеет только несколько эффективных областей действия: область действия функции и глобальная область действия.
Если переменная не находится в области видимости функции, она находится в глобальной области видимости. А глобальные переменные, как правило, плохие, так что это конструкция для хранения переменных библиотеки при себе.
источник
Это называется закрытием. Он в основном запечатывает код внутри функции, чтобы другие библиотеки не мешали ему. Это похоже на создание пространства имен в скомпилированных языках.
Пример. Предположим, я пишу:
Теперь другие библиотеки не могут получить доступ к переменной, которую
x
я создал для использования в моей библиотеке.источник
(function(){ ... return { publicProp1: 'blah' }; })();
. Очевидно, что не совсем параллельно пространству имен, но это может помочь думать об этом таким образом.Вы также можете использовать замыкания функций в качестве данных в больших выражениях, как в этом методе определения поддержки браузером некоторых объектов html5.
источник
Помимо сохранения локальных переменных, очень удобно использовать при написании библиотеки с использованием глобальной переменной, вы можете дать ей более короткое имя переменной для использования в библиотеке. Он часто используется при написании плагинов jQuery, поскольку jQuery позволяет отключить переменную $, указывающую на jQuery, с помощью jQuery.noConflict (). Если он отключен, ваш код все еще может использовать $ и не прерываться, если вы просто сделаете:
источник
источник
Мы также должны использовать «использовать строгий» в функции объема, чтобы убедиться, что код должен выполняться в «строгом режиме». Пример кода показан ниже
источник