Использование "window", "document" и "undefined" в качестве аргументов в анонимной функции, которая обертывает плагин jQuery
Честно говоря, я не знал, как сделать заголовок короче.
Я узнал, как написать плагин jQuery, изучив источник SlidesJS плагин. Когда я столкнулся с чем-то новым, я просто спросил своего хорошего друга Google и большую часть времени получил удовлетворительный ответ. Честно говоря, я никогда не прилагал больших усилий. Все, что я знаю, это то, что $
является (вероятно) сокращенным конструктором объектов jQuery и что $()
и jQuery()
- это то же самое, что и при включении jQuery.
В последнее время я попытался понять науку jQuery и как написать плагин jQuery хороший. Я столкнулся с очень хорошей статьей в которой автор перечислил несколько шаблонов для создания плагина jQuery. Поскольку все остальное было слишком сложным для меня, мне понравился первый: легкий старт. Теперь вот код для указанного шаблона.
/*!
* jQuery lightweight plugin boilerplate
* Original author: @ajpiano
* Further changes, comments: @addyosmani
* Licensed under the MIT license
*/
// the semi-colon before the function invocation is a safety
// net against concatenated scripts and/or other plugins
// that are not closed properly.
;(function ( $, window, document, undefined ) {
// undefined is used here as the undefined global
// variable in ECMAScript 3 and is mutable (i.e. it can
// be changed by someone else). undefined isn't really
// being passed in so we can ensure that its value is
// truly undefined. In ES5, undefined can no longer be
// modified.
// window and document are passed through as local
// variables rather than as globals, because this (slightly)
// quickens the resolution process and can be more
// efficiently minified (especially when both are
// regularly referenced in your plugin).
// Create the defaults once
var pluginName = 'defaultPluginName',
defaults = {
propertyName: "value"
};
// The actual plugin constructor
function Plugin( element, options ) {
this.element = element;
// jQuery has an extend method that merges the
// contents of two or more objects, storing the
// result in the first object. The first object
// is generally empty because we don't want to alter
// the default options for future instances of the plugin
this.options = $.extend( {}, defaults, options) ;
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype.init = function () {
// Place initialization logic here
// You already have access to the DOM element and
// the options via the instance, e.g. this.element
// and this.options
};
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[pluginName] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin( this, options ));
}
});
}
})( jQuery, window, document );
Я включил комментарии, чтобы ссылаться на них в моих вопросах.
У меня есть грубая идея, почему window
и document
были включены в аргумент анонимной функции, которая обертывает плагин (я не знаю, что еще назвать), потому что он указан в комментариях, он sorta kinda сокращает время выполнения. Но как это работает? Любой аргумент указанной анонимной функции, переносящий плагин, передается туда где? И как они рассматриваются в плагине?
Обычно я делал $(window).resize(function(){})
, но в этом случае это не работает. Если я делаю console.log(window)
внутри функции плагина, он говорит "undefined".
Это подводит меня к другому вопросу: что такое undefined? Разве это не тип данных, который присваивается объекту, который не определен в области видимости? Как это можно передать в качестве аргумента? Разве аргументы не должны быть объектами? В комментариях написано несколько строк, но я не понимаю ни слова об этом: < поэтому мы можем гарантировать, что его значение действительно undefined > whaaa?
Подводя итог:
- Что в действительности означает
function($)
?
- Почему я должен включать
window
, document
и undefined
в качестве аргументов function($)
?
- Если я это сделаю, как мне получить доступ к фактическим объектам
window
и document
?
-
undefined
что и почему?
Прощай, пожалуйста. Я никогда не изучал язык программирования как предмет для явной цели написания приложений. Я изучил базовый C для написания аппаратно-ориентированных низкоуровневых подпрограмм для крошечных микроконтроллеров и что-то вроде этого. Я изучил С++ широко и немного Java самостоятельно. Просто чтобы вы знали, чего ожидать.
Ответы
Ответ 1
Когда вы пишете такую функцию, как:
(function (foo, bar) {
return foo.getElementById(bar);
})(document, "myElement")
то функция немедленно вызывается с аргументами document
и "myElement"
для параметров foo
и bar
. Поэтому внутри функции foo.getElementById(bar)
эквивалентно document.getElementById("myElement")
.
Аналогично, в вашем примере плагина вы сразу вызываете функцию с аргументами jQuery, document, window
.
Что в действительности означает function($)
?
$
просто представляет ссылку на объект jQuery
, который передается в функцию обертки. Позже, когда анонимная функция вызывается с помощью (jQuery, window, document)
, ссылка $
внутри функции ссылается на объект jQuery
. Это делается по ряду причин, не в последнюю очередь из того, что $
быстрее вводить. Он также позволяет пользователю применять ваш плагин в оболочке к конкретному экземпляру jQuery
, создаваемому, возможно, с помощью jQuery.noConflict()
.
Почему я должен включать window
, document
и undefined
в качестве аргументов function($)
?
Вам не нужно включать их. Исходное авторское рассуждение состоит в том, что назначение опорных функций-локальных переменных для их сокращения сократит время, необходимое для решения этих переменных. Я утверждаю, что сбережения незначительны; Я лично не стал бы беспокоиться, если бы не использовал много ссылок на window
и/или document
.
Что касается undefined
, цель оригинального автора в том, чтобы включить это, чтобы убедиться, что кто-то не изменил глобальную переменную undefined
в EcmaScript 4 (изменить: на самом деле ECMAScript 3 - версия 4 никогда не делала этого) или ранее, Опять же, я не могу представить, как эта проблема возникает. Если вы действительно обеспокоены тем, что это может быть проблемой, просто включите что-то вроде этого в свою функцию:
if(typeof undefined !== "undefined") {
undefined = void 0;
}
Если я это сделаю, как мне получить доступ к действительным объектам window
и document
?
Все, что вам нужно сделать, это убедиться, что вызов функции в конце вашей анонимной функции проходит в фактических параметрах (jQuery, window, document). Или не включайте аргументы window
и document
в свою подпись функции. В любом случае, вы будете ссылаться на фактические объекты, независимо от уровня косвенности.
undefined
что и почему?
undefined
- глобальная переменная типа "undefined". Поля, которые не были инициализированы, точно равны (===) до undefined. Это позволяет программисту различать намеренно нулевое значение и простой неинициализированный. В ECMAScript 5 и более поздних версиях undefined
доступен только для чтения. До этого возможно, что другой код может изменить значение undefined
. Вы всегда можете получить истинное значение undefined
с выражением void 0
... как в myUndefinedVar = void 0;
.
Ответ 2
Что означает function($)
?
Передача $
в качестве аргумента вашей функции позволяет использовать стенографический объект jQuery
, который, как вы четко определили, является просто псевдонимом объекта jQuery
(также взгляните на jQuery.noConflict()
).
Почему я должен включать window
, document
и undefined
в качестве аргументов function($)
? У меня есть грубая идея, почему окно и документ были включены в аргумент анонимной функции, которая обертывает плагин (я не знаю, что еще можно назвать), потому что в комментариях указано, что оно sorta сокращает время выполнения, Но как это работает? Любой аргумент указанной анонимной функции, переносящий плагин, передается туда где?
Передача window
и document
, поскольку локальные переменные со временем сокращают время выполнения, потому что проще и быстрее получить доступ к локальной переменной, чем глобальная переменная, потому что локальные переменные являются первыми в цепочке. Какой ответ отвечает на ваш второй вопрос: аргументы передаются внутри анонимной функции scope, что в конечном итоге делает анонимную функцию: создать закрытие.
Эти аргументы передаются в конце вашей функции, где вы видите последнюю скобку. Переменная window
в вашем закрытии относится к global window
, потому что вы передали ее в конце.
Причина, по которой вы проходите undefined
, заключается в том, что undefined
является запутанным беспорядком Javascript. В принципе, undefined
является свойством глобального объекта, то есть является переменной, singleton. Он не защищен, это означает, что его можно переопределить. Это означает, что у вас может быть undefined
, который фактически определен.
Пройдя undefined
, вы убедитесь, что даже если кто-то испортился с undefined
в глобальной области (никогда не доверяйте глобальной области!:)), вы все равно получите правильный undefined
.
Кроме того, к undefined
относятся те же соображения производительности.
Если я это сделаю, как мне получить доступ к фактическому окну и объектам документа?
Вы уже обращаетесь к ним, потому что передаете их в свою функцию. И как таковой вы можете ими манипулировать.
Ответ 3
Прежде чем ответить подробно, позвольте мне заметить, что в отличие от других языков программирования, javascript является немного странным по двум причинам: во-первых, он был создан в спешке, это означало, что многие вещи не улучшались или не выполнялись хорошо. Во-вторых, он был принят в Интернете очень, очень быстро, и Microsoft скопировала язык очень быстро и очень точно (включая ошибки на языке). Результатом этого является то, что попытка исправить ошибки в дизайне языка была сложной и/или невозможной, поскольку они не хотели нарушать совместимость с существующими веб-сайтами.
Теперь перейдите к деталям:
Что в действительности означает функция ($)
Ничего особенного. В функции javascript и именам переменных разрешено использовать буквы a-z
, включая верхний регистр, цифры 0-9
и символы $
и _
. Нет никаких других ограничений на то, как они могут быть использованы. Хотя есть руководящие принципы и соглашения, некоторые из которых упомянуты самой языковой спецификацией, некоторые из них выросли с сообществом разработчиков.
Следовательно, $
- это просто имя переменной. Нет никакой разницы между:
function foo ($) {alert($)}
и
function foo (x) {alert(x)}
Это просто имя, выбранное для параметра. Однако спецификация настоятельно предполагает, что $
не должен использоваться кодом, написанным людьми. Это нормально для сгенерированного компьютером кода (например, компилятор coffeescript), но не нормально для обычных скриптов. С другой стороны, настоятельно рекомендуется в сценариях, которые используют jQuery, что $
всегда ссылаются на объект jQuery (который, кстати, также является функцией, которая отлично подходит для javascript, поскольку функции являются объектами).
Поскольку вы пишете jQuery, значение function ($)
является анонимной функцией, которая принимает один аргумент, а аргумент, который он ожидает, является объектом jQuery.
Почему я должен включать окно, документ и undefined в качестве аргументов функции ($)?
Возможно, одной из ошибок дизайна в javascript является отсутствие поддержки констант и/или неизменяемых/защищенных переменных/объектов. Таким образом, window
, document
и undefined
являются фактически регулярными глобальными переменными - каждый может переназначить их на что-либо.
Ниже приведен сумасшедший, но действительный код javascript:
window = 42;
Ни один здравомыслящий программист не сделает этого, но тем не менее это возможно. Разработчики jQuery были очень обеспокоены этим, и поэтому jQuery пытается использовать реальные window
, document
и undefined
в плагинах на случай, если кто-то настолько сумасшедший, чтобы делать сумасшедшие вещи.
Одна из особенностей javascript заключается в том, что аргументы функции переопределяют глобальные переменные. Поэтому, если какая-либо из вышеперечисленных переменных была захвачена кем-то другим, они переназначаются на свои имена в функции.
Если я это сделаю, как мне получить доступ к реальным объектам окна и документа?
Вы должны передать правильные window
, document
и undefined
в качестве аргументов с именем window
, document
и undefined
в функцию. Выполнение чего-либо еще означает, что вы больше не имеете доступа к объектам window
, document
и undefined
.
Есть сумасшедшие обходные пути, которые вы можете попробовать, чтобы попытаться захватить объект window
(также известный как глобальный объект), и оттуда вы можете получить трюк document
. Код jQuery на самом деле является обходным путем для возврата undefined
в случае его захвата.
undefined что и почему?
Как вы правильно сказали. undefined
- это значение, которое javascript предоставляет объявляемым вещам, но не имеет назначенных им значений. Но в javascript undefined
есть только глобальная переменная. Если вы не коснетесь его, оно первоначально имеет значение undefined
(круговая логика, я знаю). Но его можно изменить:
undefined = 'boom!';
И отныне все переменные undefined будут иметь значение "boom!"
. Последняя спецификация языка javascript фактически запрещает переназначение на undefined, но на сегодняшний день только Safari делает это.
Опять же, никакой здравомыслящий программист не сделает этого.
Ответ 4
Включение идентификатора в список параметров фактически совпадает с объявлением переменной в теле функции, например.
function bar(foo) {
}
эквивалентно
function bar(foo) {
var foo;
}
но, конечно, вы просто сделаете первый, если хотите передать значение foo.
Основная причина:
(function($) {
// use $ here instead of jQuery
}(jQuery));
заключается в том, что когда jQuery был выпущен, Prototype.js уже некоторое время использовал "$" как идентификатор своей основной функции. Вышеупомянутый шаблон позволяет использовать jQuery и prototype.js на одной странице, используя "$" в качестве идентификатора для разных вещей.
Передача в документе и окне - это, в лучшем случае, микро-оптимизация, которая не имеет особого преимущества. Он не предоставляет никакой защиты от того, что им назначаются разные значения, чем ожидалось. Просто не беспокойтесь и используйте окно и документ внутри функции как глобальные идентификаторы.
Включая undefined в параметры и не передавая его, это не является разумным способом обеспечения undefined действительно undefined, поскольку он все равно может быть затронут, если значение случайно передано. Более безопасный способ:
(function() {
var undefined;
...
}());
Теперь вы определенный, что undefined в области действия функции действительно есть undefined. Или если вы хотите назначить:
(function() {
var undefined = void 0;
...
}());
Но это просто дополнительная набрав.