Какова цель обертывания целых файлов Javascript в анонимные функции, такие как"(function () {...) ()"?
Я читал много Javascript в последнее время, и я заметил, что весь файл завернут, как показано ниже .JS файлы для импорта.
(function() {
...
code
...
})();
в чем причина для этого, а не простой набор функций конструктора?
8 ответов:
обычно это пространство имен (см. ниже) и управление видимостью функций-членов и/или переменных. Думайте об этом как об определении объекта. Плагины 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 ... })(), вы делаете код внутри литерала функции (что означает, что весь "объект" на самом деле является функцией). После этого вы самостоятельно вызываете функцию (final()). Так что основное преимущество этого как я уже говорил, что вы можете частные методы/функции и свойства:(function() { var private_var; function private_function() { //code } })()в первом примере globalFunction () была публичной функцией, которая могла быть вызвана для доступа к публичной функциональности, но в приведенном выше примере как вы ее называете? Здесь функция самопроизвольного вызова автоматически запускает код при запуске. Так же, как вы можете добавить initMyStuff(); в верхней части любого .JS-файл и он будет автоматически запускаться как часть глобальной области, эта функция самопроизвольного вызова также будет автоматически run, хотя, поскольку это безымянная функция, ее нельзя вызвать несколько раз, как initMyStuff() может быть.
аккуратная вещь заключается в том, что вы также можете определить вещи внутри и выставить их во внешний мир так (пример пространства имен, так что вы можете в основном создать свою собственную библиотеку/плагин):
var myPlugin = (function() { var private_var; function private_function() { } return { public_function1: function() { }, public_function2: function() { } } })()теперь вы можете позвонить
myPlugin.public_function1(), но вы не можете получить доступprivate_function()! Так что довольно похоже на определение класса. Чтобы понять это лучше, я рекомендую следующие ссылки для некоторые дальнейшие чтения:EDIT
я забыл упомянуть. В этом финале
(), вы можете передать все, что вы хотите внутри. Например, при создании плагинов jQuery вы передаетеjQueryили$вот так:(function(jQ) { ... code ... })(jQuery)Итак, что вы здесь делаете, это определение функция, которая принимает один параметр (называемый
jQлокальная переменная, и известно только для этой функции). Затем вы самостоятельно вызываете функцию и передаете параметр (также называемыйjQuery, а этой один из внешнего мира и ссылка на сам фактический jQuery). Нет острой необходимости делать это, но есть некоторые преимущества:
- вы можете переопределить глобальный параметр и дать ему имя, которое имеет смысл в локальная область.
- существует небольшое преимущество в производительности, поскольку быстрее искать вещи в локальной области вместо того, чтобы подниматься по цепочке областей в глобальную область.
- есть преимущества для сжатия (минификации).
ранее я описал, как эти функции запускаются автоматически при запуске, но если они запускаются автоматически, кто передает Аргументы? Этот метод предполагает, что все параметры задаются как глобальные переменная. Поэтому, если jQuery не был определен как глобальная переменная, этот пример не будет работать и не может быть вызван каким-либо другим способом, поскольку наш пример является анонимной функцией. Как вы можете догадаться, одна вещь jquery.js во время его инициализации определяет глобальную переменную "jQuery", а также более известную глобальную переменную"$", которая позволяет этому коду работать после jquery.js включен.
короче
резюме
в самой простой форме этот метод направлен на обертывание кода внутри область действия функции.
это помогает уменьшает шансы:
- конфликтуя с другими приложениями/библиотеками
- загрязняя главный (глобальный наиболее вероятно) объем
это не определить, когда документ готов - это не какой-то
document.onloadниwindow.onloadон широко известен как
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
если вы вернетесь к основам, вы узнаете, что:
expression: что-то оценивать значение. то есть3+11/xstatement: строка(ы) кода делает что-то, но это делает не оценить значение. т. е.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:
- developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Function_constructor_vs._function_declaration_vs._function_expression
- Javascript: разница между оператором и выражением?
- Слова Против Заявление
Демистификации Области
одна вещь, которую можно было бы задаться вопросом: "что происходит, когда вы не определяете переменную "правильно" внутри функции-т. е. вместо этого делаете простое назначение?"
(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) глобальная область определяется
Javascript в браузере действительно имеет только несколько эффективных областей: область функций и глобальная область.
Если переменная не находится в области функции, она находится в глобальной области. И глобальные переменные, как правило, плохие, так что это конструкция, чтобы сохранить переменные библиотеки для себя.
Это называется закрытие. Он в основном запечатывает код внутри функции, чтобы другие библиотеки не мешали ему. Это похоже на создание пространства имен на компилируемых языках.
пример. Предположим, я напишу:
(function() { var x = 2; // do stuff with x })();сейчас другие библиотеки не могут получить доступ к переменной
xЯ создал для использования в моей библиотеке.
вы можете использовать закрытие функций как данные в больших выражениях, а также в этом методе определения поддержки браузера для некоторых объектов 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; })() }
помимо сохранения локальных переменных, очень удобно использовать при написании библиотеки с использованием глобальной переменной, вы можете дать ей более короткое имя переменной для использования в библиотеке. Он часто используется при написании плагинов jQuery, так как jQuery позволяет отключить переменную$, указывающую на jQuery, используя jQuery.noConflict(). Если он отключен, ваш код все равно может использовать $ и не ломаться, если вы просто делаете:
(function($) { ...code...})(jQuery);
- чтобы избежать столкновения с другими методами / библиотеками в том же окне,
- избегайте глобальной области, сделайте ее локальной областью,
- чтобы ускорить отладку (локальная область),
- JavaScript имеет только область действия функции, поэтому он также поможет в компиляции кодов.
мы также должны использовать 'use strict' в функции scope, чтобы убедиться, что код должен выполняться в "строгом режиме". Пример кода показан ниже
(function() { 'use strict'; //Your code from here })();
Comments