Какова цель обертывания целых файлов 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 () была общедоступной функцией, которую можно было вызвать для доступа к общедоступной функциональности, но в приведенном выше примере как вы ее называете? Здесь функция self-invoking автоматически запускает код при запуске. Как вы можете добавить initMyStuff(); в верхней части любой .JS-файл и он будет автоматически запускаться как часть глобальной области, эта функция самозвания также будет автоматически выполнить, хотя, поскольку это неназванная функция, ее нельзя вызывать несколько раз, как 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). Нет никакой настоятельной необходимости делать это, но есть некоторые преимущества:
- вы можете переопределить глобальный параметр и дать ему имя, которое имеет смысл в локальная область.
- есть небольшое преимущество в производительности, так как быстрее искать вещи в локальной области вместо того, чтобы идти вверх по цепочке областей в глобальную область.
- преимущества для обжатия (minification).
ранее я описал, как эти функции запускаются автоматически при запуске, но если они запускаются автоматически, кто передает Аргументы? Этот метод предполагает, что все параметры задаются как глобальные переменная. Поэтому, если 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
) будет "частным" и доступным только в пределах области функций (как говорит Вивин Палиат). Другими словами, эти переменные не видны / достижимы вне функции. смотрите live demo.
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/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
поэтому, как только соответствующая модификация будет добавлена к тому, что когда-то было нашим "альтернативным кодом", мы вернемся к тому же коду, который используется в Примере "объясненный код"
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 в браузере действительно имеет несколько эффективных областей: область функций и глобальная область.
Если переменная не находится в области функций, она находится в глобальной области. И глобальные переменные, как правило, плохие, поэтому это конструкция для хранения переменных библиотеки для себя.
Это называется закрытие. Он в основном запечатывает код внутри функции, чтобы другие библиотеки не мешали ему. Это похоже на создание пространства имен на компилируемых языках.
пример. Предположим, я напишу:--3-->
(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
})();