Какова цель обертывания всех файлов Javascript в анонимных функциях типа "(function() {...})()"?
Я читал много Javascript в последнее время, и я заметил, что весь файл обернут следующим образом в импортируемых файлах .js.
(function() {
...
code
...
})();
В чем причина этого, а не простой набор конструкторских функций?
Ответы
Ответ 1
Обычно это пространство имен (см. ниже) и контролирует видимость функций-членов и/или переменных. Подумайте об этом, как об определении объекта. Плагины jQuery обычно записываются так.
В Javascript вы можете встраивать функции. Итак, законно:
function outerFunction() {
function innerFunction() {
// code
}
}
Теперь вы можете вызвать outerFunction()
, но видимость innerFunction()
ограничена областью outerFunction()
, что означает, что она закрыта для outerFunction()
. Он в основном следует тому же принципу, что и переменные в Javascript:
var globalVariable;
function someFunction() {
var localVariable;
}
Соответственно:
function globalFunction() {
var localFunction1 = function() {
//I'm anonymous! But localFunction1 is a reference to me!
};
function localFunction2() {
//I'm named!
}
}
В приведенном выше сценарии вы можете вызывать globalFunction()
из любого места, но вы не можете вызвать localFunction1
или localFunction2
.
Что вы делаете, когда пишете (function() { ... code ... })()
, вы делаете код внутри литерала функции (что означает, что весь "объект" на самом деле является функцией). После этого вы вызываете свою функцию (окончательный ()
). Поэтому основным преимуществом этого, как я уже упоминал ранее, является то, что вы можете иметь частные методы/функции и свойства:
(function() {
var private_var;
function private_function() {
//code
}
})()
В первом примере globalFunction() была публичной функцией, которая может быть вызвана для доступа к общедоступным функциям, но в приведенном выше примере, как вы это называете? Здесь функция самозапуска делает код автоматически запускаемым при запуске. Так же, как вы можете добавить initMyStuff(); в начало любого .js файла, и он будет автоматически запускаться как часть глобальной области видимости, эта функция самозапуска также будет автоматически запускаться, хотя, поскольку она является неназванной функцией, ее нельзя вызывать несколько раз, например, initMyStuff().
Оптимально то, что вы также можете определять вещи внутри и выставлять их во внешний мир, поэтому (пример пространства имен, чтобы вы могли в принципе создать свою собственную библиотеку/плагин):
var myPlugin = (function() {
var private_var;
function private_function() {
}
return {
public_function1: function() {
},
public_function2: function() {
}
}
})()
Теперь вы можете вызвать myPlugin.public_function1()
, но вы не можете получить доступ к private_function()
! Это довольно похоже на определение класса. Чтобы понять это лучше, я рекомендую следующие ссылки для дальнейшего чтения:
ИЗМЕНИТЬ
Я забыл упомянуть. В этом финале ()
вы можете передать все, что захотите внутри. Например, когда вы создаете плагины jQuery, вы проходите в jQuery
или $
следующим образом:
(function(jQ) { ... code ... })(jQuery)
Итак, что вы здесь делаете, это определение функции, которая принимает один параметр (называемый jQ
, локальная переменная и известный только этой функции). Затем вы вызываете вызов функции и передаете параметр (также называемый jQuery
, но этот из внешнего мира и ссылка на собственно jQuery). Нет надобности делать это, но есть некоторые преимущества:
- Вы можете переопределить глобальный параметр и дать ему имя, которое имеет смысл в локальной области.
- Существует небольшое преимущество в производительности, так как быстрее искать вещи в локальной области, а не перемещаться по цепочке областей видимости в глобальную область.
- Есть преимущества для сжатия (минимизации).
Раньше я описывал, как эти функции запускаются автоматически при запуске, но если они автоматически запускаются, кто передает аргументы? Этот метод предполагает, что все параметры определяются как глобальные переменные. Поэтому, если jQuery не был определен как глобальная переменная, этот пример не будет работать и не может быть вызван каким-либо другим способом, поскольку наш пример является анонимной функцией. Как вы могли догадаться, одна вещь, которую выполняет jquery.js во время ее инициализации, определяет глобальную переменную 'jQuery', а также более известную глобальную переменную $$, которая позволяет этому коду работать после включения jquery.js.
Ответ 2
Вкратце
Резюме
В своей простейшей форме этот метод нацелен на перенос кода внутри области функций.
Это помогает снизить шансы:
- столкновение с другими приложениями/библиотеками
- (наиболее вероятный глобальный) охват
Он не обнаруживает, когда документ готов - это не что-то вроде document.onload
или window.onload
Он широко известен как Immediately Invoked Function Expression (IIFE)
или Immediately Invoked Function Expression (IIFE)
Self Executing Anonymous Function
.
Обоснование кода
var someFunction = function(){ console.log('wagwan!'); };
(function() { /* function scope starts here */
console.log('start of IIFE');
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})(); /* function scope ends */
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
В приведенном выше примере любая переменная, определенная в функции (т.е. Объявленная с использованием var
), будет "закрыта" и доступна только в пределах области функции (как это делает Вивиан Палиат). Другими словами, эти переменные не видны/недоступны вне функции. Смотрите демо-версию.
Javascript имеет функцию определения области. "Параметры и переменные, определенные в функции, не видны вне функции и что переменная, определенная где угодно внутри функции, видима всюду внутри функции". (от "Javascript: хорошие части").
Подробнее
Альтернативный код
В конце концов, код, который был ранее представлен, можно также сделать следующим образом:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
};
myMainFunction(); // I CALL "myMainFunction" FUNCTION HERE
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Смотрите демо-версию.
Корни
Итерация 1
Однажды кто-то, вероятно, подумал: "Должен быть способ избежать наименования" myMainFunction ", поскольку все, что мы хотим, это немедленно выполнить его".
Если вы вернетесь к основам, вы узнаете, что:
-
expression
: что-то оценивающее значение. т.е. 3+11/x
-
statement
: строка (коды) кода делает что-то, но не оценивает значение. т.е. if(){}
Аналогично, выражения функций оцениваются до значения. И одно из последствий (я предполагаю?) Заключается в том, что они могут быть немедленно вызваны:
var italianSayinSomething = function(){ console.log('mamamia!'); }();
Итак, наш более сложный пример:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
}();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Смотрите демо-версию.
Итерация 2
Следующим шагом является мысль "почему var myMainFunction =
если мы даже не используем его !?".
Ответ прост: попробуйте удалить это, например, ниже:
function(){ console.log('mamamia!'); }();
Смотрите демо-версию.
Это не сработает, потому что "объявления функций не вызываются".
Фокус в том, что, удалив var myMainFunction =
мы преобразовали выражение функции в объявление функции. См. Ссылки в разделе "Ресурсы" для получения дополнительной информации об этом.
Следующий вопрос: "Почему я не могу сохранить его как выражение функции с чем-то другим, кроме var myMainFunction =
?
Ответ "вы можете", и есть на самом деле много способов сделать это: добавив +
, a !
, a -
, или, может быть, обертывание в пару круглых скобок (как это теперь делается по соглашению), и больше я верю. В качестве примера:
(function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.
или
+function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console
или
-function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console
Поэтому, как только соответствующая модификация добавляется к тому, что когда-то было нашим "Альтернативным кодом", мы возвращаемся к тому же самому коду, что и тот, который используется в примере "Code Explained"
var someFunction = function(){ console.log('wagwan!'); };
(function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Подробнее о Expressions vs Statements
:
Демистификация областей
Можно только удивляться: "что происходит, когда вы НЕ определяете переменную" правильно "внутри функции, т.е. Вместо этого выполняете простое назначение?"
(function() {
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
myOtherFunction = function(){ /* oops, an assignment instead of a declaration */
console.log('haha. got ya!');
};
})();
myOtherFunction(); // reachable, hence works: see in the console
window.myOtherFunction(); // works in the browser, myOtherFunction is then in the global scope
myFunction(); // unreachable, will throw an error, see in the console
Смотрите демо-версию.
В принципе, если переменной, которая не была объявлена в ее текущей области, присваивается значение, тогда "поиск цепи видимости происходит до тех пор, пока она не найдет переменную или не попадет в глобальную область (в какой момент она ее создаст)".
Когда в среде браузера (против серверной среды, такой как nodejs) глобальная область видимости определяется объектом window
. Следовательно, мы можем сделать window.myOtherFunction()
.
Мой совет "Хорошая практика" в этой теме - всегда использовать var
при определении чего-либо: будь то число, объект или функция и даже в глобальном масштабе. Это делает код намного проще.
Заметка:
- javascript не имеет области
block scope
(Update: локальные переменные области блока добавлены в ES6.) - javascript имеет только
function scope
& global scope
(область window
в среде браузера)
Узнайте больше о области Javascript Scopes
:
Ресурсы
Следующие шаги
Как только вы получите эту концепцию IIFE
, она приведет к module pattern
, который обычно делается за счет использования этого шаблона IIFE. Повеселись :)
Ответ 3
Javascript только в браузере действительно имеет несколько эффективных областей: область действия и глобальная область.
Если переменная не находится в области функций, она находится в глобальной области. И глобальные переменные, как правило, плохие, поэтому это конструкция, позволяющая хранить переменные библиотеки для себя.
Ответ 4
Это называется замыканием. Он в основном запечатывает код внутри функции, чтобы другие библиотеки не мешали ему. Это похоже на создание пространства имен в скомпилированных языках.
Пример. Предположим, что я пишу:
(function() {
var x = 2;
// do stuff with x
})();
Теперь другие библиотеки не могут получить доступ к переменной x
, которую я создал для использования в моей библиотеке.
Ответ 5
Вы можете использовать закрытие функций как datastrong > в больших выражениях, как в этом методе определения поддержки браузера для некоторых объектов html5.
navigator.html5={
canvas: (function(){
var dc= document.createElement('canvas');
if(!dc.getContext) return 0;
var c= dc.getContext('2d');
return typeof c.fillText== 'function'? 2: 1;
})(),
localStorage: (function(){
return !!window.localStorage;
})(),
webworkers: (function(){
return !!window.Worker;
})(),
offline: (function(){
return !!window.applicationCache;
})()
}
Ответ 6
В дополнение к сохранению переменных локально, очень удобно использовать при написании библиотеки с использованием глобальной переменной, вы можете дать ей более короткое имя переменной для использования в библиотеке. Он часто используется при написании плагинов jQuery, поскольку jQuery позволяет отключить переменную $, указывающую на jQuery, используя jQuery.noConflict(). Если он отключен, ваш код все равно может использовать $и не прерывать, если вы просто выполните:
(function($) { ...code...})(jQuery);
Ответ 7
- Чтобы избежать столкновения с другими методами/библиотеками в одном окне,
- Избегайте глобальной области видимости, сделайте ее локальной областью,
- Чтобы сделать отладку более быстрой (локальная область),
- JavaScript имеет только область видимости функции, поэтому она также поможет в компиляции кодов.
Ответ 8
Мы также должны использовать "use strict" в функции scope, чтобы убедиться, что код должен быть выполнен в "строгом режиме". Пример кода, показанного ниже
(function() {
'use strict';
//Your code from here
})();
Ответ 9
Простой блок работает как IIFE в ES6
В ES6 вы можете использовать обычный блок фигурных скобок, чтобы сохранить код вне глобального пространства имен (var
сильно обескуражен!):
{
'use strict';
your stuff here
}
Протестировано в Chrome, Safari, Safari iOS, Firefox. Я понятия не имею, имеет ли этот шаблон имя, будь то хорошая практика или почему я не мог сначала найти ссылку на него вообще (до указанной выше статьи).