Как работает конструкция (function() {})() и почему люди ее используют?
(function() {})()
и его JQuery-специфичный кузен (function($) {})(jQuery)
всплывать все время в коде Javascript.
Как работают эти конструкции и какие проблемы они решают?
Примеры приветствуются
16 ответов
С ростом популярности фреймворков JavaScript, $
знак использовался во многих различных случаях. Таким образом, чтобы смягчить возможные конфликты, вы можете использовать эти конструкции:
(function ($){
// Your code using $ here.
})(jQuery);
В частности, это объявление анонимной функции, которое выполняется немедленно, передавая основной объект jQuery в качестве параметра. Внутри этой функции вы можете использовать $
ссылаться на этот объект, не беспокоясь о том, что другие области также находятся в области видимости.
Это метод, используемый для ограничения области видимости переменной; это единственный способ предотвратить загрязнение глобальных пространств имен переменными.
var bar = 1; // bar is now part of the global namespace
alert(bar);
(function () {
var foo = 1; // foo has function scope
alert(foo);
// code to be executed goes here
})();
1) Он определяет анонимную функцию и выполняет ее сразу.
2) Обычно это делается для того, чтобы не загрязнять глобальное пространство имен нежелательным кодом.
3) Вам нужно выставить некоторые методы из него, все, что объявлено внутри, будет "приватным", например:
MyLib = (function(){
// other private stuff here
return {
init: function(){
}
};
})();
Или, альтернативно:
MyLib = {};
(function({
MyLib.foo = function(){
}
}));
Дело в том, что есть много способов использовать его, но результат остается прежним.
Это просто анонимная функция, которая вызывается немедленно. Вы можете сначала создать функцию, а затем вызвать ее, и вы получите тот же эффект:
(function(){ ... })();
работает как:
temp = function(){ ... };
temp();
Вы также можете сделать то же самое с именованной функцией:
function temp() { ... }
temp();
Код, который вы называете специфичным для jQuery, является только тем, в котором вы используете в нем объект jQuery. Это просто анонимная функция с параметром, которая вызывается немедленно.
Вы можете сделать то же самое в два этапа, и вы можете сделать это с любыми параметрами:
temp = function(answer){ ... };
temp(42);
Проблема, которую это решает, состоит в том, что он создает замыкание для кода в функции. Вы можете объявить переменные в нем, не загрязняя глобальное пространство имен, тем самым уменьшая риск конфликтов при использовании одного скрипта вместе с другим.
В конкретном случае для jQuery вы используете его в режиме совместимости, где он не объявляет имя $ как псевдоним для jQuery. Отправив объект jQuery в замыкание и присвоив имя параметру $, вы все равно можете использовать тот же синтаксис, что и без режима совместимости.
Еще одна причина сделать это состоит в том, чтобы устранить путаницу в отношении того, какие рамки $
оператор вы используете. Например, чтобы вызвать jQuery, вы можете сделать:
;(function($){
... your jQuery code here...
})(jQuery);
Проходя в $
оператор в качестве параметра и вызывая его на jQuery, $
Оператор внутри функции заблокирован для jQuery, даже если у вас загружены другие фреймворки.
Здесь объясняется, что ваша первая конструкция обеспечивает область видимости для переменных.
Переменные ограничены на уровне функций в javascript. Это отличается от того, к чему вы могли бы привыкнуть в языке, таком как C# или Java, где переменные находятся в пределах блока. Это означает, что если вы объявите переменную внутри цикла или оператор if, она будет доступна для всей функции.
Если вам когда-нибудь понадобится явно указать переменную внутри функции, вы можете использовать анонимную функцию для этого. На самом деле вы можете создать анонимную функцию, а затем сразу же выполнить ее, и все переменные внутри нее будут ограничены анонимной функцией:
(function() {
var myProperty = "hello world";
alert(myProperty);
})();
alert(typeof(myProperty)); // undefined
Другое использование этой конструкции - это "захват" значений локальных переменных, которые будут использоваться в замыкании. Например:
for (var i = 0; i < 3; i++) {
$("#button"+i).click(function() {
alert(i);
});
}
Приведенный выше код заставит все три кнопки всплыть "3". С другой стороны:
for (var i = 0; i < 3; i++) {
(function(i) {
$("#button"+i).click(function() {
alert(i);
});
})(i);
}
Это заставит три кнопки всплыть "0", "1" и "2", как и ожидалось.
Причина этого заключается в том, что замыкание сохраняет ссылку на свой вмещающий кадр стека, в котором хранятся текущие значения его переменных. Если эти переменные изменятся до того, как будет выполнено замыкание, тогда замыкание увидит только самые последние значения, а не те, какими они были на момент создания замыкания. Оборачивая создание замыкания внутри другой функции, как во втором примере выше, текущее значение переменной i
сохраняется в кадре стека анонимной функции.
Это считается закрытием. Это означает, что содержащийся код будет работать в пределах своей собственной лексической области. Это означает, что вы можете определять новые переменные и функции, и они не будут конфликтовать с пространством имен, используемым в коде за пределами замыкания.
var i = 0;
alert("The magic number is " + i);
(function() {
var i = 99;
alert("The magic number inside the closure is " + i);
})();
alert("The magic number is still " + i);
Это создаст три всплывающих окна, демонстрируя, что i
в замыкании не изменяется ранее существовавшая переменная с таким же именем:
- Магическое число 0
- Магическое число внутри крышки - 99
- Волшебное число по-прежнему 0
Они часто используются в плагинах jQuery. Как объясняется в Руководстве по созданию плагинов jQuery, все переменные, объявленные внутри { }
являются частными и не видны снаружи, что позволяет лучше инкапсулировать.
Как уже говорили другие, они оба определяют анонимные функции, которые вызываются немедленно. Я обычно оборачиваю свои объявления класса JavaScript в эту структуру, чтобы создать статическую частную область видимости для класса. Затем я могу поместить в эту область константные данные, статические методы, обработчики событий или что-то еще, и они будут видны только экземплярам класса:
// Declare a namespace object.
window.MyLibrary = {};
// Wrap class declaration to create a private static scope.
(function() {
var incrementingID = 0;
function somePrivateStaticMethod() {
// ...
}
// Declare the MyObject class under the MyLibrary namespace.
MyLibrary.MyObject = function() {
this.id = incrementingID++;
};
// ...MyObject's prototype declaration goes here, etc...
MyLibrary.MyObject.prototype = {
memberMethod: function() {
// Do some stuff
// Maybe call a static private method!
somePrivateStaticMethod();
}
};
})();
В этом примере MyObject
класс присваивается MyLibrary
пространство имен, поэтому оно доступно. incrementingID
а также somePrivateStaticMethod()
не доступны напрямую за пределами области действия анонимной функции.
Это в основном для пространства имен вашего кода JavaScript.
Например, вы можете поместить туда любые переменные или функции, а снаружи они не существуют в этой области. Поэтому, когда вы заключаете все в капсулу, вам не нужно беспокоиться о столкновениях.
()
в конце означает самовозврат. Вы также можете добавить аргумент, который станет аргументом вашей анонимной функции. Я делаю это с JQuery часто, и вы можете понять, почему...
(function($) {
// Now I can use $, but it won't affect any other library like Prototype
})(jQuery);
Evan Trimboli освещает все остальное в своем ответе.
Код выше создает анонимную функцию в строке 1, а затем вызывает ее в строке 3 с 0 аргументами. Это эффективно инкапсулирует все функции и переменные, определенные в этой библиотеке, потому что все функции будут доступны только внутри этой анонимной функции.
Это хорошая практика, и причина этого заключается в том, чтобы не загрязнять глобальное пространство имен переменными и функциями, которые могут быть забиты другими частями Javascript по всему сайту.
Чтобы уточнить, как вызывается функция, рассмотрим простой пример:
Если у вас есть эта единственная строка Javascript, он будет вызываться автоматически без явного вызова:
alert('hello');
Итак, возьмите эту идею и примените ее к этому примеру:
(function() {
alert('hello')
//anything I define in here is scoped to this function only
}) (); //here, the anonymous function is invoked
Конечный результат аналогичен, потому что анонимная функция вызывается так же, как и в предыдущем примере.
Это самостоятельная функция. Вроде как стенография для письма
function DoSomeStuff($)
{
}
DoSomeStuff(jQuery);
Потому что ответы на хороший код уже приняты:) Я добавлю предложение посмотреть несколько видео Джона Резига, видео 1, видео 2 (изобретатель jQuery & master в JavaScript).
Некоторые действительно хорошие идеи и ответы, представленные в видео.
Именно этим я и занимался в тот момент, когда увидел твой вопрос.
Копируя то, что говорит Итан Браун в
Функциональные выражения позволяют нам создавать нечто, называемое немедленно вызываемым функциональным выражением (IIFE). IIFE объявляет функцию, а затем немедленно запускает ее. Теперь, когда у нас есть четкое представление об области действия и замыканиях, у нас есть инструменты, необходимые для понимания того, почему мы можем захотеть сделать это. IIFE выглядит следующим образом:
(function() {
// this is the IIFE body
})();
Мы создаем анонимную функцию, используя функциональное выражение, а затем немедленно вызываем (вызываем) эту функцию. Преимущество IIFE в том, что все внутри него имеет свою область видимости, а поскольку это функция, она может передать что-то вне области видимости:
const message = (function() {
const secret = "I'm a secret!";
return `The secret is ${secret.length} characters long.`;
})();
console.log(message);
Переменная secret безопасна внутри области IIFE и не может быть доступна извне. Вы можете вернуть из IIFE все, что хотите, и довольно часто возвращаются массивы, объекты и функции. Рассмотрим функцию, которая может сообщать о том, сколько раз она была вызвана способом, который нельзя подделать:
const f = (function() {
let count = 0;
return function() {
return `I have been called ${++count} time(s).`;
}
})();
f(); // "I have been called 1 time(s)."
f(); // "I have been called 2 time(s)."
Поскольку переменная count надежно скрыта во IIFE, ее невозможно изменить: f всегда будет иметь точное количество вызовов. Хотя переменные с областью действия блока в ES6 несколько уменьшили потребность в IIFE, они по-прежнему довольно часто используются и полезны, когда вы хотите создать замыкание и что-то из него вернуть.
function(){ // some code here }
способ определить анонимную функцию в JavaScript Они могут дать вам возможность выполнять функцию в контексте другой функции (в противном случае у вас может не быть этой способности).