jQuery constructor init parameter analysis

  • 2020-06-12 08:26:31
  • OfStack

In my last essay, I analyzed the constructor of jQuery. The real constructor is init, which has a prototype method in the jQuery object. By keeping references between the prototype object of init and the prototype object of jQuery, the instance of init can call the prototype method of jQuery as if it were instance 1 of jQuery. Here's how the behind-the-scenes constructor init works:


init: function( selector, context, rootjQuery ) {

...

}

You can see that this method takes three arguments, the first two of which were passed in by the jQuery method


var jQuery = function( selector, context ) {

// The jQuery object is actually just the init constructor 'enhanced'

return new jQuery.fn.init( selector, context, rootjQuery );

},

In principle, Selector can input any value, but not all values are meaningful. Only undefined, DOM elements, strings, functions, jQuery objects, and ordinary JavaScript objects are valid. This parameter is usually filled in but no error can be reported


console.log($());
//[constructor: function, init: function, selector: "", jquery: "1.7.1", size: function ... ]

Context can be passed in as an execution context or range, or either the DOM element, jQuery object, or 1 of the regular JavaScript object

Parameter rootjQuery: The jQuery object containing the document object is used when the document.getElementById () lookup fails. selector is a selector expression and context and selector are not specified as functions.

The following 12 cases are discussed one by one according to the different parameters

1.selector can be converted to false


// Handle $(""), $(null), or $(undefined)

if ( !selector ) {

return this;

}

The comments in the source code are made clear that return does nothing when it comes to these three cases

2. The parameter selector is the DOM element

For example: $(document)


// Handle $(DOMElement)

if ( selector.nodeType ) {

this.context = this[0] = selector;

this.length = 1;

return this;

}

As long as the dom element has a node type, then make this node the first element of the jquery object and assign a value to the context context. The length attribute is jQuery and the stereotype attribute defaults to 0

// The default length of a jQuery object is 0

length: 0,
Once you have one element, change the length attribute to 1. The return this operation keeps the result of the function as an jQuery object so that a chained call like $(document).each () can be implemented. The resulting such {0: document, context: document, length: 1... } objects, in fact all cases will eventually become objects of this form, except jQuery prototype properties and methods are dom nodes acquired and arranged in Arabic numerals, so we can use the form of $(selector)[0] instead of $(selector).get(0) to obtain the dom object. Such as:


<!doctype html>

<html>

  <head>

   <title></title>

  </head>

  <body>

    <div></div>

    <div></div>

    <div></div>

  </body>

  <script src='jquery-1.7.1.js'></script>

  <script>

   console.log($('div'));

/*[div, div, div, prevObject: jQuery.fn.jQuery.init[1], context: document, selector: "div", constructor: function, init: function ... ]

0: div
1: div
2: div
context: document
length: 3
prevObject: jQuery.fn.jQuery.init[1]__proto__: jQuery[0]
selector: "div"
.
*/
  </script>

</html>


3. The argument is the special string "body"

Since the body element is only 1 in 1 document object, it is listed separately for processing


// The body element only exists once, optimize finding it

if ( selector === "body" && !context && document.body ) {

this.context = document;

this[0] = document.body;

this.selector = selector;

this.length = 1;

return this;

}

There are three conditions that must be met at the same time, and the second condition that must have no context is not clear to me. The seemingly normal writing of $(' body',document) is also ignored by this situation.


 console.log($('body',document));

 /*

 jQuery.fn.jQuery.init[1]

0: body

context: document

length: 1

prevObject: jQuery.fn.jQuery.init[1]

selector: "body"

__proto__: jQuery[0]

*/

Although the result is the same as $('body'), it is treated as two cases, possibly because body only has one context, which can only be document. It is not necessary to add it, otherwise it is necessary to determine whether the context is document. The third condition is that ES115en.ES116en must exist. In what case do two conditions meet ES117en.ES118en and do not exist? The first is that the js code is loaded before the html code. This is a common mistake for beginners.

$(function(){...})

or

$(document).ready(function(){...})

In fact, these two samples are 1 method. dom will analyze after loading this 1 block. We can do a test for this html code as follows:


<!doctype html>
 
<html>
 
  <head>
 
   <title></title>
 
    <script src='jquery-1.7.1.js'></script>
 
   <script>
 
       $('body')
 
  </script>
 
  </head>
 
  <body>
 
    <div></div>
 
    <div></div>
 
    <div></div>
 
  </body>
 
</html>

Then jQuery source code output selector, context and ES140en.body


console.log(selector+context+document.body);

// The body element only exists once, optimize finding it

if ( selector === "body" && !context && document.body ) {

this.context = document;

this[0] = document.body;

this.selector = selector;

this.length = 1;

return this;

}

So even though we only wrote one and actually executed it four times, only the last one is going to be the result of our call, and the last one is going to be bodyundefinednull where the first two satisfy but the last one is null. Recalling that undefined will be rewritten in the overall architecture of jQuery 1, will ES150en.body be rewritten as null? It doesn't seem like it will when I try to modify it in the code, so this condition is to prevent the execution without loading html

The fourth type is other than the above string case, the case is more put in the next article.

This is the end of this article, I hope you enjoy it.


Related articles: