Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using 'window', 'document' and 'undefined' as arguments in anonymous function that wraps a jQuery plugin

Tags:

Honestly, I didn't know how to make the title shorter.

I learnt how to write a jQuery plugin by studying the source of SlidesJS plugin. When I encountered something new, I just asked my good friend Google and most of the times, got a satisfactory answer. Honestly though, I never made much effort. All I know is that $ is (probably) a shorthand jQuery object constructor and that $() and jQuery() are the same thing provided jQuery is included.

Recently, though, I tried to understand the science behind jQuery and how to write a good jQuery plugin. I came across a very good article in which the author listed several templates for creating a jQuery plugin. Since the rest were too complex for me to understand, I liked the first one: A Lightweight Start. Now, here is the code for the said template.

/*!  * 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 ); 

I have included the comments so as to refer to them in my questions.

I have a crude idea why window and document have been included in the argument of the anonymous function that wraps the plugin (I don't know what else to call it) because it is given in the comments that it sorta kinda shortens the execution time. But how does that work? Any argument of the said anonymous function wrapping the plugin gets passed on to where? And how are these addressed in the plugin?

Normally, I would do $(window).resize(function(){}) but that doesn't work in this case. If I do console.log(window) inside the Plugin function, it says 'undefined'.

Which brings me to the other question which is: what is undefined? Isn't it a data type that is assigned to an object that isn't defined in the scope? How can it be passed as an argument? Don't the arguments have to be objects? There are a few lines written about this in the comments, but I don't understand a word of it: <so we can ensure that its value is truly undefined> whaaa?

To sum up:

  • What indeed is meant by function($)?
  • Why should I include window, document and undefined as arguments of function($)?
  • If I do it, how do I access the actual window and document objects?
  • undefined what, and why?

Please go easy on me. I never studied programming language as a subject for the express purpose of writing applications. I studied basic C for writing hardware oriented low-level routines for tiny core microcontrollers and that's just about it. I did learn C++ extensively and a bit of Java on my own. Just so you'd know what to expect.

like image 828
Zia Ur Rehman Avatar asked Apr 03 '13 01:04

Zia Ur Rehman


1 Answers

When you write a function like:

(function (foo, bar) {     return foo.getElementById(bar); })(document, "myElement") 

then the function is immediately called with arguments document and "myElement" for parameters foo and bar. Therefore, inside the function, foo.getElementById(bar) is equivalent to document.getElementById("myElement").

Similarly, in your plugin example, you are immediately calling the function with the arguments jQuery, document, window.

What indeed is meant by function($)?

The $ simply represents a reference to a jQuery object that is passed in to the wrapper function. Later, when the anonymous function is called with (jQuery, window, document), the $ reference inside the function references the jQuery object. This is done for a number of reasons, not least of which is that $ is quicker to type. It also allows the user to apply your plugin in wrapper to a particular instance of jQuery, produced perhaps by jQuery.noConflict().

Why should I include window, document and undefined as arguments of function($)?

You don't need to include these. The original author's reasoning is that assigning function-local variables to reference these will shorten the time it takes to resolve these variables. I assert that the savings are negligible; I personally wouldn't bother unless I used a lot of references to window and/or document.

As for undefined, the original author's purpose in including this is to ensure that someone hasn't altered the undefined global variable in EcmaScript 4 (edit: actually ECMAScript 3 -- version 4 never made it) or earlier. Again, I can't envision this problem cropping up. If you're truly worried that this could be a problem, just include something like this in your function:

if(typeof undefined !== "undefined") {     undefined = void 0; } 

If I do it, how do I access the actual window and document objects?

All you have to do is make sure that the function call at the end of your anonymous function passes in the actual (jQuery, window, document) parameters. Or, don't include the window and document arguments in your function signature. Either way, you will be referring to the actual objects, regardless of the level of indirection.

undefined what, and why?

undefined is a global variable of type "undefined". Fields that have not been initialized are exactly equal (===) to undefined. It allows the programmer to differentiate between a deliberately null value and a simple uninitialized one. In ECMAScript 5 and later, undefined is read only. Prior to that, it is possible that other code could modify the value of undefined. You can always get the true value undefined with the expression void 0... as in myUndefinedVar = void 0;.

like image 115
bchociej Avatar answered Oct 23 '22 05:10

bchociej