2010-04-26 4 views
148

Вы когда-нибудь смотрели под капотом на JQuery 1,4 исходного кода и заметил, как он воплощен в следующим образом:Как работает этот синтаксис JavaScript/JQuery: (function (window, undefined) {}) (window)?

(function(window, undefined) { 

    //All the JQuery code here 
    ... 

})(window); 

я прочитал статью о JavaScript Namespacing и еще один под названием "An Important Pair of Parens , «поэтому я знаю кое-что о том, что здесь происходит.

Но я никогда не видел этот синтаксис раньше. Что это такое undefined делать там? И почему window необходимо передать, а затем снова появиться в конце?

+3

Я хотел добавить, что Пол Ирланд об этом говорит в этом видео: http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/ – Mottie

+0

@ Bergi вы отметили мой вопрос как дубликат другого, но я задал вопрос почти за год до дубликата. Бросок должен быть наоборот. – dkinzer

+0

@ dkinzer: Это не о том, что вас спрашивают раньше, речь идет о самом высоком качестве ответа. По общему признанию, в этом случае это шея и шея, но я нашел ответ CMS лучшим. Приходите на http://chat.stackoverflow.com/rooms/17/, чтобы обсудить это, хотя – Bergi

ответ

154

неопределенное является нормальной переменной и может быть изменен только с undefined = "new value";. Таким образом, jQuery создает локальную «неопределенную» переменную, которая ДЕЙСТВИТЕЛЬНО не определена.

Переменная окна сделана локальной по соображениям производительности. Потому что, когда JavaScript просматривает переменную, она сначала переходит через локальные переменные, пока не найдет имя переменной. Когда он не найден, JavaScript проходит через следующую область и т. Д., Пока он не фильтрует глобальные переменные. Поэтому, если переменная окна сделана локальной, JavaScript может быстрее ее искать. Дополнительная информация: Speed Up Your JavaScript - Nicholas C. Zakas

+1

Спасибо! это было очень информативное видео. Я думаю, вам нужно отредактировать свой ответ, чтобы сказать «переменная окна сделана локальной». Я думаю, что это лучший ответ. Я подсчитал и обнаружил, что объект окна вызывается не менее 17 раз в исходном коде JQuery.Таким образом, существенный эффект при перемещении окна в локальную область. – dkinzer

+0

@ DKinzer О да, вы, конечно, это сделано локально. Рад, что я мог бы помочь вам =) – Vincent

+1

Согласно этому обновленному тесту http://jsperf.com/short-scope/5, проходящее «окно» на самом деле медленнее, когда приходит, чтобы получить константу окна через jQuery и особенно плохо для Safari , Поэтому, хотя «неопределенный» имеет прецедент, я не совсем уверен, что «окно» особенно полезно во всех случаях. – hexalys

5

window передается таким образом, что на тот случай, если кто-то решит переопределить объект окна в IE, я предполагаю то же самое для undefined, если он будет повторно назначен каким-то образом позже.

Верхний window в этом скрипте просто называет аргумент «окно», аргумент, который является более локальным, чем глобальная ссылка window, и это то, что будет использовать код внутри этого закрытия. window в конце фактически указывает, что передать для первого аргумента, в данном случае текущее значение window ... надеюсь, что вы не испортили window, прежде чем это произойдет.

Это может быть легче думать, показывая наиболее типичный случай, используемый в JQuery, плагин .noConflict() обработку, так что для большинства коды вы можете использовать $, даже если это означает что-то другого чем jQuery вне этой сферы :

(function($) { 
    //inside here, $ == jQuery, it was passed as the first argument 
})(jQuery); 
+0

Спасибо. Это имеет большой смысл. Хотя, я думаю, что ответ - это комбинация этого и того, что говорит К.Закас. – dkinzer

+0

@DKinzer Я боюсь, что я не C. Закас;) – Vincent

+0

@ Винсент, извините, что :-) – dkinzer

15

Другие пояснили undefined. undefined - это как глобальная переменная, которая может быть переопределена на любое значение. Этот метод заключается в том, чтобы не допустить, чтобы все неопределенные проверки были нарушены, если кто-то написал, скажем, undefined = 10. Аргумент, который никогда не передается, гарантированно действителен undefined независимо от значения переменной undefined.

Причины прохождения окна можно проиллюстрировать следующим примером.

(function() { 
    console.log(window); 
    ... 
    ... 
    ... 
    var window = 10; 
})(); 

Что делает журнал консоли? Значение window Объект правильно? Неправильно! 10? Неправильно! Он регистрирует undefined.Javascript интерпретатор (или JIT компилятор) переписывает это таким образом -

(function() { 
    var window; //and every other var in this function 

    console.log(window); 
    ... 
    ... 
    ... 
    window = 10; 

})(); 

Однако, если вы получаете переменную window в качестве аргумента, не вар и, следовательно, никаких сюрпризов.

Я не знаю, делает ли это jQuery, но если вы переопределяете локальную переменную где угодно в вашей функции по какой-либо причине, неплохо заимствовать ее из глобальной области.

52

Неопределенное

Объявив undefined в качестве аргумента, но никогда не передавая значение это гарантирует, что оно всегда не определено, так как это просто переменная в глобальной области, которые могут быть перезаписаны. Это делает a === undefined безопасной альтернативой typeof a == 'undefined', что экономит несколько символов. Это также делает код более дружественным к minifier, так как undefined можно сократить до u, например, сохранив еще несколько символов.

Window

Передача window как аргумент сохраняет копию в локальной области, которая влияет на производительность: http://jsperf.com/short-scope. Все обращения к window теперь должны будут перемещаться на один уровень за пределы области действия. Как и в случае с undefined, локальная копия снова позволяет более агрессивную оценку.


Sidenote:

Хотя это, возможно, не было намерения разработчиков JQuery, переходящая в window позволяет библиотеку быть легко интегрирован в серверных средах Javascript, например node.js - где нет глобального объекта window. В такой ситуации необходимо заменить только одну строку, чтобы заменить объект window на другой. В случае jQuery может быть создан и передан объект mock window с целью очистки HTML (такая библиотека может быть jsdom).

+2

+1 для упоминания «Минимизация», мне хотелось бы +2 для jsperf. Минимизированная версия «(функция (a, b) {}) (окно);' - ' a' и 'b' намного короче, чем' window' и 'undefined' :) – gnarf

+0

+1 Я уже слышал о цепочке видимости *, но забыл термин. Благодаря! – alex

+0

Это также альтернатива использованию void (0), предназначенная по той же причине: void (0) - безопасный способ получить неопределенное значение. – glmxndr

5

Протестировано с 1000000 итерациями. Такая локализация не влияла на производительность. Даже ни одна миллисекунда в 1000000 итераций. Это просто бесполезно.

+2

Не говоря уже о том, что замыкание несет всю переменную вместе с экземпляром функции, поэтому, если у вас есть 100 байтов в закрытии и 1000 экземпляров, что на 100 килобайт больше памяти. –

+0

@AkashKava и @Semra, я не думаю, что этот тест действительно объясняет, почему вы будете проходить в окне в реальной ситуации. Повышение производительности будет наблюдаться только тогда, когда у вас есть глубоко вложенные блокировки, которые будут обращаться к этой переменной дальше по цепочке областей видимости. очевидно, если ваша функция находится всего в одном шаге от цепочки областей действия от переменной, вы не увидите большого выигрыша. но если это было waaaay там и нужно было получить '' 'window''', вы могли бы получить некоторую прибыль от локальной копии. – gabereal

+0

@gabereal новые механизмы JavaScript разрешают закрытие во время самой компиляции, при закрытии во время выполнения нет увеличения производительности. Я сомневаюсь, что есть какое-то измеримое усиление производительности, если вы так уверены, вы можете создать пример jsperf для демонстрации производительности. Единственная производительность, которую мы получаем, - это изолирование замыканий, что приводит к лучшей минимизации, которая уменьшает размер и производительность, достигается более быстрой загрузкой и анализом сценария. –

Смежные вопросы