jQuery constructor init parameter analysis continues

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

If selector is some other string it gets a lot more complicated


// Handle HTML strings
if ( typeof selector === "string" ) {...} 

Start to deal with different situations


// Are we dealing with HTML string or an ID?
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}

In If, the first character is" < "The last character is" > If the length is greater than 3, assume selector is html simple tag, such as $(' < div > ') but remember to only assume "assume" such as $(' < sdfadfadf > ') The same goes here. The match array is then modified to [null,selector,null]. match is the variable declared in the init function. It is used as a tool to distinguish the parameter types


init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;

If the condition of if is not satisfied, a regular is called to get the result of match, which is the variable declared in the jQuery constructor


// A simple way to check for HTML strings or ID strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,

This regex is mainly used to distinguish the html string from the id string. The second comment explains that in order to avoid location.hash-based XSS attacks, the # (#9521) is added to quickExpr, meaning that we can find the explanation on the jQuery website.

First visit http: / / bugs. jquery. com/and then search the corresponding value

The result of quickExpr.exec (selector) can be an array, the first element of the array is the matched element, the rest are the grouped matched elements, the regular has two groups ( < [\w\W]+ > )[^ > ] and ([\w\-]*)1 is the label and 1 is the id value. match will get the results. First of all, the single label is not in the form of [null, selector, null] without the regular form. The following is proved in the code:


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

In html, we create an jQuery object and then output the match result in init method:


if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}
 console.log(match); // [null, "<div>", null];

Let's change the parameter 1 to $(' #div') and see the result 1 more time


["#div", undefined, "div", index: 0, input: "#div"]

There is a more special case of $(' < div > 123') and then we have one more result


["<div>dewrwe", "<div>", undefined, index: 0, input: "<div>dewrwe"]

We can see that id is always in the third element and the tag value is kept in the second element, in the last case with $(' < div > ') makes no difference because the dom element is generated without processing the first element. Based on this result, we can go on to analyze the next judgment.

According to the results of match, there will be three cases


if ( match && (match[1] || !context) ) {

     ...

} else if ( !context || context.jquery ) {

    ...

} else {

  ...

}

The first case satisfies the condition that match1 must have a value, and match[1] is the second element that holds the tag has a value or no context, but it doesn't seem to have id what's up? No, by analyzing the results of match you can see that the second element with no value must be the result of the id selector, whereas id is the only one that does not require a write context (the written context will also work correctly, but will use Sizzle instead of dealing with the same as body here). Well, the first condition comes in

1. The label

$(' < div > $(' ') < div > $(' 123 ') < div > 23213213 < /div > ')...

2. No context id $(' #div')

The first condition is further subdivided internally:


// HANDLE: $(html) -> $(array)
if ( match[1] ) {

  ...

// HANDLE: $("#id")

}else{

}

So obviously if is for tags and else is for id, so let's see what we do with tags, right


context = context instanceof jQuery ? context[0] : context;
doc = ( context ? context.ownerDocument || context : document );
 
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
ret = rsingleTag.exec( selector );
 
if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
 
} else {
selector = [ doc.createElement( ret[1] ) ];
}
 
} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}
 
return jQuery.merge( this, selector);

context under the first amendment 1 value, if the object is jQuery took him into a dom element method is to use subscript before this theory said, then have to deal with the doc variables, if context no give doc document assignment if there is ownerDocument attribute exists and the value that is dom elements or document if not dom elements such as ordinary js object then the object assigned to doc variables. This is followed by a regular judgment on selector, which is also declared in the jQuery constructor for the purpose of judging single tags such as < div > such


// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,

Then give ret variables, the results based on ret value and handled separately divided according to the single tag and complex ret values exist that is matched to the single label and then according to whether context ordinary object is divided into two cases isPlainObject is a common object, the method of detection is if it is a common object, using js native methods createElement incoming labels and create elements in an array, and so is convenient for later merged with jquery object, Then assign the array value to selector, and then call attr method with object impersonation. Here attr actually has three parameters, while we usually use api with two parameters. In fact, there are many similar cases in jQuery, and the same method has two interfaces inside and outside. The second argument is the context of the object form, because attr can resemble


$("img").attr({ src: "test.jpg", alt: "Test Image" });

What this gives us is that we can pay $(' < div > ',{id:'div'}) is also supported. If it's not an object, create the element without regard to attributes. Again, put the element you created in the array. If ret doesn't have a value then it's a complicated tag like $(' < div > 231 < /div > '), the native js will not be able to handle the problem. You need to call another method jQuery.buildFragment to handle the problem. Finally, the merged result is returned


return jQuery.merge( this, selector );

Unlike return this, which returns the result of merge's execution, his task is to merge the dom elements that were created in the array into jquery elements, and finally to {0: div,length:1... } such an object form. In this way, the case of Jane label is finished.

And then else deals with id


elem = document.getElementById( match[2] );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;

It's easy to call the native id selector directly but bug appears on some systems

The annotation is very clear on the blackberry system, which is that the element doesn't exist anymore but it still matches so if you add the parent, the element that doesn't exist doesn't have a parent. There is another case where the ie and opera browsers match the name value and make a judgment

if ( elem.id !== match[2] ) {

If it does happen, you can't use the native method, you can use the find method, which is the sizzle engine, and in most normal cases you can just put the element you get into this and then change the value of context. Ok finally finished analyzing the first large branch. And then the second branch according to match


// Are we dealing with HTML string or an ID?
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}
0

Here it is if there is no context or if the context is an jquery object and this is easier it is just to use the find method rootjQuery is $(document)

And then the last case of the string is if none of the above is true


return this.constructor( context ).find( selector );

This. constructor is jQuery and it's still using the find method.

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


Related articles: