Столкнулся в этом примере с синтаксисом, который раньше не встречал:
for (var state in aus) {
...
(function (st, state) {
...
})(aus[state], state);
}
Что означает эта конструкция внутри цикла?
Ответы
Ответ 1
Чтобы избежать недостоверных данных, которых в данном треде достаточно, вставлю и свои пять копеек:
на подобный вопрос я уже отвечал - Проблема с обработчиками в цикле, только там подобный синтаксис был решением проблемы
собственно, что это IIFE - Immediately-Invoked Function Expression, и для чего е
можно применять уже описано здесь же, но почему этот подоход используется именно в скрипте из ссылки:
for (var state in aus) {
...
(function(st, state) {
st[0].onmouseover = function() {
/* мы знаем, что функция onmouseover - асинхронная, т.е. мы не може
достоверно сказать когда она выполнится, но точно после выполнения цикла, следоватльно
после выполнения цикла aus[state] - будет указывать на последнее значение, которые было получено в цикле, что не соответсвует нашим ожиданиям, для этого aus[state] копируется в переменную st, которая на каждой итерации цикла указывает на необходимый aus[state], тоже самое с переменной state*/
...
};
st[0].onmouseout = function() {
/*здесь ситуация аналогичная*/
...
}
})(aus[state], state);
}
поэтому всегда, когда в цикле оперируем с асинхронными функциями, будь то таймауты, обработчики событий или колбэки, всегда искользуется подобная техника
Тонкости ECMA-262-3. Часть 6. Замыкания.
Ответ 2
Это сделано чтобы не засорять глобальную область видимости локальными переменными и и меть копии самых важных глобальных например в JQuery. То есть:
(function(window, undefined){
var a = 28.2;
var z = new Object();
//...
window.myVal = a != undefined;
})(window);
Этот код в глобальную область видимости добавляет только myVal и имеет собственны
экземпляр window и undefined (undefined не ключевое слово а глобальная переменная) на случай если кто то напишет после исполнения этого кода:
window = 1; undefined = "Hack";
то (если ф -ции не передаются аргументы они принимают значение undefined) у нас будет истинное значение undefined и истинное значение window.
Эта и подобные темы неоднократно обсуждались в том числе и мной и я в конечном счёте пришёл к выводу что чтобы понять JS нужно прочитать JavaScript The definitive guide
Ответ 3
Эксклюзивно для пользователя @theshock:
Основной недостаток этого ответа не в
том, что он - некорректный по своей
сути. Нет, я уверен, что книга, с
которой вы это всё скопировали может
быть очень хорошей (кстати, что это за
книга?), но в нём нет ответа на
вопрос в топике, который дал,
например, Spectre.
Вы только что подтвердили, что не читали ответа (либо прочти как попало) и следовательно, говорите то что приходит в голову (мягко говоря).
Цитирую:
книга, с которой вы это всё скопировали может быть очень хорошей (кстати, что это за книга?)
То есть вы не знаете что это за книга, но уверенно говорите что это было скопировано - не зная откуда? И делаете явное заявление?
Цитирую повторно (чтобы подтвердить что Вы не читали ответа):
кстати, что это за книга?
Еше до UPDATE 1,
Есть строка:
На заметку: Кложуры хорошо описаны в
книге Джона Резига (автора Jquery) -
Secrets of JavaScript Ninja (2012)
Это был копи паст? Пф, хорошо вперед - в гугл, найдите вот эти книги (если есть желание):
John Resig - Pro JavaScript Techniques (2006)
David Flanagan - JavaScript The Definitive guide
John Resig - Secrets of JavaScript Ninja (2012)
Сделайте это. Не поленитесь.
Открывайте. Вперед. Найдите те строки где описано ТОЧНО ТАКЖЕ как в ответе.
Если вы найдете ХОТЯ БЫ ЧТО-ТО ПОХОЖЕЕ(чего конечно не произойдет), то тогда у меня проблемы с головой.
На случай если Вы этого не сделаете:
P.S когда-то JS я учил по этим книгам, и могу сказать точно, что:
David Flanagan - JavaScript The Definitive guide - (function(){})() - Не описываются
John Resig - Pro JavaScript Techniques (2006) - описано базовое использование. Про пространства имен ни слово.
Но не надо верить мне на слово - обязательно проверьте это.
И еще:
Если вещи принято называть "одними именами" - это не значит, что все люди копи пастят друг у друга.
В данном случае это была просто фразы
Это называется Closure или Wrapper.
Как указано выше, по мимо использования оригинальных глобальных обьектов внутри тела функции,
возиожности Closure далеко не ограничеваются на этом. Это лишь малая часть применения
Далее цитирую:
Основная проблема этого ответа - огромное количество воды и совершенно левой информации.
Это бездумно скопированных кусок книги и это ярко видно на первых двух абзацах:
ОК.
Смотрим на заголовок вопроса:
Что в Javascript значит синтакс ( function(){...} )( param1, param2); ?
То есть исходя из этого, весь ответ НЕ ИМЕЕТ АБСОЛЮТНО НИКАКОГО ОТНОШЕНИЯ к
( function(){...} )( param1, param2) ? - т.е заголовку вопроса?
И все примеры никак не связаны с заголовком вопроса?
Вам совет:
Когда в следующий раз Вы будете кого-то критиковать:
1) Сначала составьте список конкретных и четких "недоразумений".
2) Обязательно соберите КОНКРЕТНЫЕ доказательства на них.
и вперед - прямо "в морду", как говорится.
Но вы этого не сделали, и я немного был поражен наглостью, и беспочвенностью
поэтому ставлю Вам -1 лично от себя.
Эклюзив для пользователя @Shock. Часть 2
вы зря не ответили под моим ответом -
так теряется ветвь дискуссии. Я и
правда не смог нагуглить ответ, но у
меня была вполне понятная
аргументация. В этом куске в самом
начале своего комментария вы
отсылаетесь к какому-то непонятному
куску:
Это называется Closure или Wrapper.
Как указано выше, по мимо
использования оригинальных глобальных
обьектов внутри тела функции,
возиожности Closure далеко не
ограничеваются на этом. Это лишь малая
часть применения
Вы очередной раз подтвержаете, что ни читали ответа - но при этом снова делаете какие-то нелепые выводы относительно всего происходящего.
"Кусок" будет непонятным если не читать от начала до конца и последовательно.
Фраза/выражение "Как указано выше" - означачает, что, что-то наподобие того что был
только что описано конкретным примером имеет место относительно последущего обьяснения/примера.
Сейчас у меня есть предположение, что
вы отсылались к другому комментарию,
но когда я зашёл на эту страницу - ваш
комментарий был первым. Я так понимаю,
это моё неправильное понимание ваших
слов. Если это так, то прошу прощения
за несправедливое предположение на
счёт копипасты из книги.
Сами понимаете что так делать не нужно. Прежде чем высказыватся на все 100% нужн
прочитать все комменты а затем высказать своё мнение и обвинять тем более. Иначе легко оказатся в неловком положении.
Тем не менее, стоило прочитать не только заголовок вопроса, но и его
содержимое, а там явно указан
определённый случай, который является
более узким. В силу незнания автор не
знал, как его правильно
категоризировать, потому заголовок был
слишком общим.
Ваша ошибка в том, что вы бросились отвечать на общий заголовок,
не вдаваясь в детали самого вопроса.
Автор вопроса сказал обобщенно, что никогда раньше не сталкивался и не имеет понятия что это такое вообще.
То есть, нужно было сразу начать обьяснять о том как "изолировать/изолируются" переменны
в том примере, при ЭТОМ НЕ ОТВЕЧАЯ НА ВОПРОС ЧТО ЭТО? человеку который видит эту "конструкцию впервой?!" тем самым вводя еще в большее заблуждение? - IMHO
ОК
@Shock давайте не будем продолжать, т.к это может перерасти в большую дискуссию и уже не несет никакой пользы читателям/автору вопроса. Давайте на этом остановимся.
САМ ОТВЕТ
Внимание читатели
Ни один из ответов данных здесь - не является испечрпывающим на все 100%.
Кто хочет более подробно изучить, качайте мною предложенну книгу (см. внизу) и само собой читайте остальные ответы (пользователей @Spectre, @Rules) на этой странице.
Это называется Closure или Wrapper, ровно так же как Immediately-Invoked Function Expression
Но название Immediately-Invoked Function Expression не совсем корректно (и не всегд
логично-уместно), т.к мы сразу получим противоречие, если просто присвоим это переменной.
Вот так: var foo = ( function(){} )();
В чем противоречие? Оно в том что типа Immediately-Invoked Function Expression больш
не Immediately-invoked, поскольку она будет вызвана только при явном вызове, а не при немедленном-самостоятельным.
Кому интересно, вот статья на английском, которая аналогичным образом это обьяснит, только более детально.
Статью, начинать читать отсюда:
I’d like to see JavaScript community
members adopt the term
“Immediately-Invoked Function
Expression” and “IIFE” in their
articles and presentations, because I
feel it makes understanding this
concept a little easier, and because
the term “self-executing anonymous
function” isn’t really even accurate:
И не забыть:
Hopefully these examples have made it
clear that the term “self-executing”
is somewhat misleading, because it’s
not the function that’s executing
itself, even though the function is
being executed
Все кто считает, что названия Closure или Wrapper неверны -
повторяю(уже который раз) - все: 1) Сначала в гугл качаем книгу
Secrets of JavaScript Ninja (Автор : John Resig, разработчик Jquery) 2) Открываем страницу 44. Читаем. Смотрим на Листинг 3.18
Как указано выше (из ответа пользователя @Rules), по мимо использования оригинальны
глобальных обьектов внутри тела функции, возиожности Closure далеко не ограничеваются на этом. Это лишь малая часть применения.
Все сделано чтобы не засорять
глобально именное пространство
-- это не совсем так... я тоже так думал когда только начинал
Предназначение №1 - Имитация NameSpace
Поскольку сам стандарт ECMAScript не предусматривает поддержку именных пространст
- (namespaces), Closure имитирует их, посредством импорта и экспорта глобальных переменных.
Все сводится к имитированной реализации нэймспэйсов.
Это легко проверить на практике:
Как видно из примера, функция sayTest() выведет разные сообщения (она не будет перезаписана
- значит функция с одним и тем же именем работает по-разному.(заметка для C++ программистов: это не перегрузка)
Предназначение №2 - Имитация класса
Так как, ECMAScript 1.7 не предусматривает возмости реализации классов "на прямую", то разработчикам приходится имитировать классы через функции-обьекты.
Применение
var foo = (function()( // Это Closure функция, но класс одновременно. см.внизу
var foo = null; // приватное свойство
function sayHi() { // публичный метод
alert('Hi!');
}
function sayGoodBye(){ // // публичный метод
alert('Good Bye');
}
return { // т.к как это все таки функция, нужно вернуть значения
sayHi : sayHi,
sayGoodBye : sayGoodBye
}
))();
foo.sayGoodBye(); // вызовет Alert c гуд бай
foo.sayHi(); // вызовет Alert c Хай
Это практически эквивалетно литералу:
var foo = {
sayGoodBye : function(){ ... },
sayHi : function(){ ... }
};
Только с одним качественным отличием - проблема доступа к методам и членам класса
Для того чтобы в литерале (только что упомянатому) получить доступ к другому методу/член
класса нужно вызвать так: foo.MethodName(). Но есть одна проблема - что если имя переменной foo изменить на bar?! Тогда все будет JavaScript парсер будет завершатся фатально с ошибкой типа: foo is undefined - и чтобы решить данную проблему придется так везде переименовать foo в bar.
Это неудобно, создает нелепые зависимости (от имени переменной) и как следствие - это просто АНТИ-ПАТТЕРН.
В то время как в имитированной классе через Closure можно вызывать функции в не зависимости от переменной, вот так:
var foo = (function(){
function testA(){
alert('Test');
}
function testB(){
testA(); // <-- вот так, на прямую
}
})();
Это удобно, читабельно и легко для отладки.
Предназначение №3 - модификация существующих переменных (в частности обьектов) без рефлексии текущего глобального пространства. На примере:
Это например бывает очень полезно при написании библиотек, потому что:
1) Позволит унаследовать/расширить существующие обьекты только при подключению через - src атрибут.
2) Так как реализация будет в теле Closure, это не будет рефлекторно относительн
глобального именного пространства - что гарантирует, то что не будет случайных перезаписей функций или переменных.
Когда это использовать
В большинстве случаев разработчики используют wrapper для задания своих обьекто
внутри, чтобы писать библиотеки. Примеры - Prototype.js, Jquery.js, Backbone.js...
Например, в Jquery-UI, каждый модуль заключен в Closure/Wrapper/Immediately-Invoked Function Expression,
(function($){
// код модуля/плагина - т.е наследования/расширение текущих методов обьекта Jquery
// Не "задевая" глобальное пространство
})(Jquery);
Используй для написания библиотек (СОВЕТ)
Но не стоит этим злоупотреблять, однако. Используй враппер, только по конкретно
причине, если это необходимо, поскольку : 1) Они требуют чуть больше памяти (только если их не мало) 2) Они могут затруднять понимание кода.
На заметку:
Кложуры хорошо описаны в книге Джона Резига (автора Jquery) - Secrets of JavaScript Ninja (2012)
ОФФТОП
No more comments.
Все дискуссии были удалены
Не пишите больше комменты. Они меня уже начинают раздражать слегка.
Не согласны? Ставьте -1 это ваше право. (Не надо кидать линки на статьи Дмитрия Сошникова, ок?). Согласны/нашли что-то полезное - плюсуйте. Или игнорируйте, но не надо комментов.
Ответ 4
Чтобы было понятней:
for (var i=0; i<10; i++) {
var j = i;
setTimeout( function(){console.log(j);} , 100)
}
Выведет десять девяток.
for (var i=0; i<10; i++) {
(function(j){
setTimeout( function(){console.log(j);} , 100)
})(i);
}
Выведет числа от 0 до 9.
Ответ 5
Единственный полный, корректный и емкий ответ был у Spectre. Его и надо слушать.
Тот приём, который использован в топике называется Immediately-Invoked Function Expressio
и используется для того, чтобы ассинхронные коллбеки внутри цикла могли получить ссылку на корректный элемент.
По остальным комментариям
P.S. в примере автора НЕ замыкание, перепутал.
И опять перепутали, в примере автора замыкание. И вообще любая функция создаёт замыкание
Например, внутри функции можно получить доступ к aus. Это и достигается замыканием. Читаем, например, JavaScript-Garden:
Одним из самых мощных инструментов JavaScript'а считаются возможность создавать замыкани
— это такой приём, когда наша область видимости всегда имеет доступ к внешней области
в которой она была объявлена. Собственно, единственный механизм работы с областями видимости в JavaScript — это функции: т.о. объявляя функцию, вы автоматически реализуете замыкания
ivanpopelyshev правильно понял вопрос, но привёл только пример, не объяснив идеи
Ответ Rules вообще мимо. Конечно, иногда функции используются для этого, но тут не тот случай:
Это сделано чтобы не засорять глобальную область видимости локальными переменными и и меть копии самых важных глобальных например в JQuery.
И самый главный ответ heavy_metal_fan, который так критиковал Spectre и совершенн
правильно. Я прям вспомнил годы своей бурной молодости, 2-й курс университета, когда я глубоко не понимаю, это грёбанное "Экономико-математическое моделирование", но экзамен писать надо и пишу всё, что попадётся в шпорах.
Основная проблема этого ответа - огромное количество воды и совершенно левой информации. Это бездумно скопированных кусок книги и это ярко видно на первых двух абзацах:
Это называется Closure или Wrapper.
Как указано выше, по мимо
использования оригинальных глобальных
обьектов внутри тела функции,
возиожности Closure далеко не
ограничеваются на этом. Это лишь малая
часть применения
Мы ещё не начали читать комментарий, а он уже отсылает куда-то в прошлое, куда-т
в пустоту. Комментарий отлично пересказывает главу какой-то книги, возможно даже хорошей
например Флагнана или Резига. Но вы вывалили сюда ВСЁ про функции. Кусок про Предназначение №1 - Имитация NameSpace, кусок про Предназначение №2 - Имитация класса, кусок про Предназначение №3 - модификация существующих переменных
Вы понемногу дошли до ключевой фразы, которая является правильным ответом на вопро
топик-стартера - Immediately-Invoked Function Expression, но потом, в объяснениях снова скатились не туда.
Основной недостаток этого ответа не в том, что он - некорректный по своей сути. Нет
я уверен, что книга, с которой вы это всё скопировали может быть очень хорошей (кстати, что это за книга?), но в нём нет ответа на вопрос в топике, который дал, например, Spectre.
Ответ 6
Создается анонимная функция и сразу же вызывается.
Ответ 7
Эта конструкция называется функциональным выражением. Все, что оборачивается в скобк
в JavaScript считается выражением. Если скобки убрать, получим ошибку объявления функции без указания имени функции. Например хром выведет такую ошибку:
`SyntaxError: Unexpected token (`
Комментариев нет:
Отправить комментарий