JQuery3.1.1 Source code Interpretation (a) "jquery overall Architecture"

Source: Internet
Author: User
Tags closure constructor extend object object shallow copy tostring
jQuery Overall Architecture

First of all, jquery is a development framework, its popularity can not be described in words, when you casually open a website, more than half of the direct use of jQuery. Perhaps, a few years ago, a front-end engineer, as long as he would write jQuery, can work without worry. Although react and Vue have been very hot lately, many of the wonderful methods and logic in jQuery deserve to be learned by every front-end person.

As with its many frameworks, always put the interface outside to call, the interior is often a closure, to avoid environmental variables pollution.

Let's take a look at some of the major features of jquery: $ (' #id ') function to directly generate jquery objects $ (' #id '). CSS (). html (). Hide () Chained call

On the chain call, I think a bit of foundation is easy to implement, the function end return this can, mainly to introduce the no new implementation of the object creation. no new function implementation

The following is a normal function, and it is clear that it will fall into a dead loop:

var jquery = function () {
  return new jquery ();
}
Jquery.prototype = {
  ...
}

This dead loop comes too suddenly, and jquery () creates a new jquery,new jquery and creates a new jquery ...

jquery uses an init function instead of the direct new function name, and also takes into account the separation scope in jquery:

var jQuery = function () {
  return new jQuery.prototype.init ();
}
Jquery.prototype = {
  constructor:jquery,
  init:function () {
    this.jquery = 1.0;
    return this;
  },
  jquery:2.0,
  each:function () {
    console.log (' each ');
    return this;
  }
}
jquery (). jquery//1.0
jQuery.prototype.jquery//2.0

jquery (). each ()//Error

It appears to be working correctly, but the problem is with JQuery (). each ()/error, not accessing the each function. In fact, new JQuery.prototype.init () returns to the instance of who it is. is an instance of the Init function, so this in the INIT function has no meaning.

So, if:

var JQ = JQuery ();
jq.__proto__ = = = Jquery.prototype;
Jq.each = = = JQuery.prototype.each;

If you can implement the proto point of the above problem, the prototype function call problem is resolved, but in fact :

var JQ = JQuery ();
jq.__proto__ = = = JQuery.prototype.init.prototype; True

In fact, the proto of JQ is a prototype that points to the Init function, so we can put JQuery.prototype.init.prototype = Jquery.prototype, at this time, the function call is logical, and the use of the reference, pointing to the same prototype object, do not need to worry about the loop problem. In fact, that's exactly what JQuery did.

var jQuery = function () {
  return new jQuery.prototype.init ();
}
Jquery.prototype = {
  constructor:jquery,
  init:function () {
    this.jquery = 1.0;
    return this;
  },
  jquery:2.0,
  each:function () {
    console.log (' each ');
    return this;
  }
}
JQuery.prototype.init.prototype = Jquery.prototype;
JQuery (). each ()//' Each '
jQuery Internal structure diagram

Before the internal diagram, say Jquery.fn, it is actually a reference to prototype, pointing to Jquery.prototype,

var jQuery = function () {
  return new jQuery.prototype.init ();
}
Jquery.fn = Jquery.prototype = {
  ...
}

So why use FN to point to prototype. I consulted some of the information, it seems that the following answer is more pertinent: introduction. Don't you think FN is much better than prototype?

Borrow a picture from the Internet:

As you can see from this diagram, there are two common interfaces on the Window object, namely $ and jQuery:

Window.jquery = window.$ = JQuery;

The Jquery.extend method is a method of copying objects, including deep copies, which will be explained in detail later, and put aside for the time being.

The following relationship may be a bit messy, but carefully read the previous introduction, you should be able to understand. FN is prototype, so the FN and prototype properties of JQuery point to the FN object, and the Init function itself is the method in Jquery.prototype, and the prototype prototype of the INIT function points to FN. Chained calls

The benefit of chained calls is that the code written is very concise, and the code returns the same object, improving the efficiency of the Code.

As already mentioned, add return this after the prototype function that has no return value:

var jQuery = function () {
  return new jQuery.fn.init ();
}
Jquery.fn = Jquery.prototype = {
  constructor:jquery,
  init:function () {
    this.jquery = 3.0;
    return this;
  },
  each:function () {
    console.log (' each ');
    return this;
  }
}
JQuery.fn.init.prototype = Jquery.fn;
JQuery (). each (). each ();
"Each"
//' Each '
Extend

One of the important functions in jquery is extend, which can expand the properties and methods of jquery itself, and extend the properties and methods of the prototype.

First of all, the function of the extend function, there are probably two, if the parameter has only one object, that is, to extend the object into the jquery namespace, which is called the extension of jquery. If the function receives more than one object, it represents a copy of the property that copies the properties of the subsequent objects to the first object, including the deep copy, the non-reference copy, and the first parameter, if true, to represent a deep copy.

Jquery.extend (target);//JQuery extension
jquery.extend (target, obj1, Obj2,..); /Shallow Copy 

This is the JQuery 3 after the Extend function source code, made its own comments:

Jquery.extend = JQuery.fn.extend = function () {var options, name, SRC, copy, Copyisarray, clone, target = Arguments[0] ||

  {}, I = 1, length = arguments.length, deep = false;

    Determines if the deep copy if (typeof target = = = "Boolean") {depth = target; Parameter shift target = Arguments[i] | |
    {};
  i++; }//Handling target is a string or strange case, isfunction can determine if the target is a function if (typeof target!== "Object" &&!jquery.isfu
  Nction (target)) {target = {};
  }//To determine if jquery expands if (i = = length) {target = this;//This is a marker that can point to jquery or to Jquery.fn i--; } for (; i < length; i++) {//null/undefined to determine if (options = Arguments[i])! = NULL) {//This is already unified,
        Regardless of the parameters of the preceding function, the task now is target object, and options is the Copy object for (name in options) {src = target[name];

        copy = Options[name];
        Prevents a dead loop and skips itself if (target = = = copy) {continue;
  }//Deep copy, and the object being copied is objects or array//This is the focus of deep copy      if (deep && copy && jquery.isplainobject (copy) | | (Copyisarray = Array.isarray (copy))))
            {//Description The copied object is an array if (Copyisarray) {Copyisarray = false; clone = src && array.isarray (src)?
          SRC: [];
          The object being copied is objects} else {clone = src && jquery.isplainobject (src)? src: {};

          }//Recursive copy sub-attribute Target[name] = Jquery.extend (deep, clone, copy);
        Regular variable, direct =} else if (copy!== undefined) {Target[name] = copy;
}}}}//Return the modified object return target; }

The Extend function conforms to the parameter processing specification in JQuery, which is one of the more standard. JQuery has a set of parameters to handle, always liking dislocation to make each position variable and their name the same. For example, target object, if the first parameter is a Boolean, the deep assignment target, and the target is moved backward one bit, if there is only one parameter object, that is, the extension of JQuery, the target assignment this, the current pointer I minus one 。

The logic of this approach is complex, but it offers a very big advantage: the processing logic behind it requires only one. Target is the object we want to copy, and the options are the objects to be copied, and the logic is very clear.

Extend function also needs the main point, Jquery.extend = JQuery.fn.extend, not only JQuery object and this function, even the prototype also has, then how to distinguish the object is where to expand, and how to achieve.

In fact, all this has to do with the dynamic nature of this in JavaScript, target = This, where the code is placed, who executes, and this will point to who, it expands on its properties. functions derived from extend

Look at extend source code, there are some functions, just look at the name know what it is doing, I singled out to find their source. jquery.isfunction Source

jquery.isfunction = function (obj) {
    return jquery.type (obj) = = = "function";
}

It's a little too simple. There is also an important function jquery.type in JQuery, which is used for type judgment.

First, why does the traditional typeof not use. Because it's not good (there should be a crying face here):

Numbers typeof PNs = = = ' number ';
typeof 3.14 = = = ' number ';
typeof = = = ' number ';
typeof MATH.LN2 = = = ' number ';
typeof Infinity = = = ' number '; typeof NaN = = = ' number '; Despite being "Not-a-number" typeof number (1) = = = ' number ';

But never use this form!
Strings typeof "" = = = ' String ';
typeof "Bla" = = = ' String '; typeof (typeof 1) = = = ' String '; typeof always returns a string typeof string ("abc") = = = ' String ';

But never use this form!
Booleans typeof true = = = ' Boolean ';
typeof false = = = ' Boolean '; typeof Boolean (true) = = = ' Boolean ';

But never use this form! Symbols typeof symbol () = = = ' symbol ' typeof symbol (' foo ') = = = ' symbol ' typeof symbol.iterator = = ' symbol '//undefine
D typeof undefined = = = ' undefined ';
typeof declaredbutundefinedvariable = = = ' undefined '; 

typeof undeclaredvariable = = = ' undefined ';

Objects typeof {A:1} = = = ' object '; Use Array.isarray or Object.prototype.toString.call//to differentiate regular objects from arrays typeof [1, 2, 4] = = = ' object ';

typeof new Date () = = = ' object '; The following is confusing.
Don ' t use! 
typeof New Boolean (true) = = = ' object '; 
typeof new Number (1) = = = ' object ';

typeof New String ("abc") = = = = ' object ';
Functions typeof function () {} = = = ' function ';
typeof class C {} = = = ' function ';

typeof Math.sin = = = ' function '; This stands since the beginning of JavaScript typeof null = = = ' object ';

It can be seen that for some new objects, such as new number (1), an object is returned as well. Please refer to typeof MDN for details.

There are two solutions on the Internet (validity is not verified, please believe the method of JQuery), one is to use Constructor.nameObject.prototype.constructor MDN, one is to use Object.prototype.toString.call () Object.prototype.toString (), eventually JQuery chose the latter.

var n1 = 1;
n1.constructor.name;//"Number"
var n2 = new number (1);
n2.constructor.name;//"Number"

var toString = Object.prototype.toString;
Tostring.call (N1);//"[Object number]"
tostring.call (n2);//"[Object number]"

These are popular science, the principle is not much elaboration, then continue to see the source Jquery.type:

This object is used to turn the string returned by the toString function into
var class2type = {
    "[Object Boolean]": "Boolean", "
    [object number]": "Number ",
    " [Object string] ":" String ",
    " [Object Function] ":" Function ",
    " [Object Array] ":" Array ",
    " [Object Date] ":" Date ",
    " [Object RegExp] ":" RegExp ",
    " [Object Object] ":" Object ",
    " [Object Error] ":" Error ", "
    [object Symbol]": "Symbol"
}
var toString = Object.prototype.toString;

Jquery.type = function (obj) {
    if (obj = = null) {
        return obj + "";
    }
    return 
      typeof obj = = = "Object" | | typeof obj = = = "function"? 
        Class2type[tostring.call (obj)] | | "Object": 
        typeof obj;
}

Because JQuery uses the ToString method, a Class2type object is required to convert. Jquery.isplainobject

This function is used to determine whether an object is a purely object:

var Getproto = object.getprototypeof;//Gets the parent object
var hasown = class2type.hasownproperty;
var fntostring = hasown.tostring;
var objectfunctionstring = Fntostring.call (Object);

Jquery.isplainobject = function (obj) {
    var proto, Ctor;

    Exclude underfined, NULL, and non-object cases
    if (!obj | | tostring.call (OBJ)!== "[Object Object]") {
        return false;
    }

    proto = Getproto (obj);

    Objects with no prototype (e.g., ' object.create (null) ') is plain
    if (!proto) {
        return true;
    }

    Objects with prototype is plain iff they were constructed by a global Object function
    Ctor = Hasown.call (Proto, " Constructor ") && Proto.constructor;
    return typeof Ctor = = = "function" && fntostring.call (Ctor) = = = Objectfunctionstring;
}

Look at the effect:

Jquery.isplainobject ({});//True
Jquery.isplainobject ({a:1});//True
Jquery.isplainobject (New Object ()); /True

jquery.isplainobject ([]);//False
Jquery.isplainobject (new String (' a '));//False
Jquery.isplainobject (function () {});//False

In addition to these functions, there is a array.isarray (), this really does not need to introduce it. Summary

To summarize or to say a little more good, now has basically cleared the internal jQuery situation. No, also nearly, look at the following code:

 (function (window) {//jquery variable, with closure to avoid environmental pollution var jquery = (function () {var jquery = Functi
    On (selector, context) {return new JQuery.fn.init (selector, context, rootjquery);

    }; Some variable declarations Jquery.fn = Jquery.prototype = {constructor:jquery, init:function (selector, context, Roo

    Tjquery) {//The next chapter will focus on}//prototype method};

    JQuery.fn.init.prototype = Jquery.fn; Jquery.extend = JQuery.fn.extend = function () {};//introduced jquery.extend ({//A heap of static properties and methods//with extend binding, without

    is written directly on JQuery});
  return jQuery;

  })(); Tool method Utilities//Callback Function List callbacks object//Asynchronous Queue defferred object//Browser function test support//data cache//queue Queu  E//attribute operation Attributes//Event System events//Selector Sizzle//DOM traversal traversing//style manipulation CSS (calculated style, inline style)//asynchronous request Ajax//
Animation Effects//coordinate Offset, size Dimensions window.jquery = window.$ = JQuery; }) (window); 

We can see that jQuery is very ingenious overall layout thinking, for attribute method and prototype method and so on, to prevent variable pollution, etc., are doing very well. Reading frame source code is just the beginning, interesting is still behind. Reference

JQuery 2.0.3 Source Analysis Core-Overall architecture

"JQuery Source code Analysis" Reading notes (Chapter II: Constructing jquery objects)

Jquery.isplainobject () function explanation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.