Подтвердить что ты не робот

Использование "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 самостоятельно. Просто чтобы вы знали, чего ожидать.

4b9b3361

Ответ 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;
    ...
}());

Но это просто дополнительная набрав.