JQuery 2.0.3 Source Analysis Core-Overall architecture
Reading an open source framework, the most wanted to learn is the idea of design and the implementation of the skills.
Not much nonsense, jquery so many years of analysis have been written rotten, long ago to read,
But these years are to do mobile end, has been Queen Zepto, recently took some time to sweep jquery again
I will not be scripted translation source, combined with their actual experience to read it together!
On GitHub the newest is jquery-master, added AMD specification, I will take the official newest 2.0.3 to prevail
Overall architecture
The core of the jquery framework is to match elements from an HTML document and perform operations on them,
For example:
$ (). Find (). CSS () $ (). Hide (). html (' ... '). Hide ().
At least 2 questions can be found from the above notation
1. How jquery objects are built
2. How the jquery method is invoked
Analysis One: No new construction of jquery
JavaScript is a functional language, functions can implement classes, and classes are the most basic concepts in object-oriented programming.
var aquery = function (selector, context) { //constructor}aquery.prototype = { //prototype name:function () {}, age : function () {}}var a = new Aquery (); A.name ();
This is a normal use, and it's obvious that jquery doesn't play this way.
jquery does not instantiate the jquery display using the new runner or call its function directly
According to the way jquery is described
$ (). Ready () $ (). Noconflict ()
To achieve this, then jquery will be treated as a class, then $ () should be an instance of the returned class to
So change the code:
Press CTRL + C to copy the code<textarea></textarea>Press CTRL + C to copy the code
Through new Aquery (), although the return is an instance, but also can see very obvious problem, dead loop!
So how do I return a correct instance?
Instances of this in JavaScript are only related to prototypes
The jquery class can then be used as a factory method to create an instance and put this method into a Jquery.prototye prototype.
var aquery = function (selector, context) { return aQuery.prototype.init ();} Aquery.prototype = { init:function () { return this; } Name:function () {}, age:function () {}}
When executing aquery () The returned instance:
It is obvious that aquery () returns an instance of the Aquery class, so this is actually an instance of the Aquery class that is pointed to in Init.
Here's the problem. The this point of Init is the Aquery class, and if the init function is also treated as a constructor, how does the internal this handle?
Press CTRL + C to copy the code<textarea></textarea>Press CTRL + C to copy the code
This makes a mistake, because this only points to the Aquery class, so you need to design a separate scope.
Processing of jquery framework-delimited scopes
jquery = function (selector, context) { //The jquery object is actually just the Init constructor ' enhanced ' r Eturn New JQuery.fn.init (selector, context, rootjquery); },
It is clear that the instance init function constructs a new Init instance object each time to separate this and avoid interaction confusion
So if it's not the same object, then there's definitely a new problem.
For example:
var aquery = function (selector, context) { return new AQuery.prototype.init ();} Aquery.prototype = { init:function () { this.age = return this; }, name:function () {}, age : 20}//uncaught Typeerror:object [Object Object] has no method ' name ' Console.log (Aquery (). Name ())
Throws an error and cannot find this method, so it is clear that the new Init is separated from the jquery class
How do I access properties and methods on the jquery class prototype?
Is it possible to isolate scopes and use the scope of jquery prototype objects, and to access the prototype objects of jquery in the return instance?
Key points of implementation
Give the init function The JQuery prototype for later instantiationjQuery.fn.init.prototype = Jquery.fn;
Solve problems with prototype delivery, and pass the prototype of jquery to JQuery.prototype.init.prototype
In other words, jquery's prototype object overrides the Init constructor's prototype object
Because it is a reference pass, there is no need to worry about the performance of this circular reference
var aquery = function (selector, context) { return new AQuery.prototype.init ();} Aquery.prototype = { init:function () { return this; }, name:function () { return this.age },< C9/>age:20}aquery.prototype.init.prototype = Aquery.prototype;console.log (Aquery (). Name ())//20
Baidu borrowed a picture of netizens, to facilitate direct understanding:
FN explained that in fact this FN has no special meaning, just jquery.prototype reference
Analysis Two: Chained calls
Handling of DOM chained calls:
1. Save JS Code.
2. The same object is returned, which can improve the efficiency of the Code
Cross-browser chained calls are implemented by simply extending the prototype method and using the return this form.
Use the Simple Factory mode under JS to specify the same instance for all operations on the same DOM object.
This is a very simple principle.
Aquery (). Init (). Name () decomposition a = Aquery (); A.init () A.name ()
To decompose the code, it is obvious that the basic condition of the chain is the existence of the instance, and the same
Aquery.prototype = { init:function () { return this; }, name:function () { return this }}
So we're going to need a chained way to access this, because we're returning the current instance of this, and then we can access our own prototypes.
Aquery.init (). Name ()
Pros: Save code, improve code efficiency, and make your code look more elegant
The worst thing is that all of the object's methods return the object itself, meaning there is no return value, which is not necessarily appropriate in any environment.
JavaScript is a non-blocking language, so he is not blocking, but not blocking, so he needs to be driven by events, asynchronous to do some of the need to block the process of operation, so that the process is only synchronous chain, asynchronous chain jquery from the beginning of 1.5 introduced Promise, jquery.deferred later in the discussion.
Analysis Three: plug-in interface
The main framework of jquery is this, but according to the general designer's custom, if you want to add a property method for jquery or jquery prototype, also if you want to provide developers with the extension of the method, from the packaging point of view is not to provide an interface, The literal ability to understand is to extend the function rather than to look directly at modifying prototype. Friendly user interface,
JQuery supports its own extended properties, which provides an external interface, JQuery.fn.extend () to add methods to objects
As you can see from the source code of JQuery, Jquery.extend and jQuery.fn.extend are actually different references to the same method
Jquery.extend = JQuery.fn.extend = function () {
Jquery.extend extends the properties and methods of jquery itself jQuery.fn.extend the properties and methods of Jquery.fn.
With the Extend () function, you can easily and quickly extend functionality without destroying the prototype structure of jquery.
Jquery.extend = JQuery.fn.extend = function () {...}; This is even, that is, 2 points to the same function, how to achieve different functions? This is the power!
For FN and jquery are actually 2 different objects, which were previously narrated:
- When Jquery.extend is called, this is a pointer to the jquery object (jquery is a function and an Object!). ), so here's the extension on jquery.
- When JQuery.fn.extend is called, this points to the FN object, Jquery.fn and Jquery.prototype point to the same object, and the extended FN is the extended Jquery.prototype prototype object.
- This adds to the prototype method, which is the object method. So the jquery API provides the above 2 extension functions.
The realization of Extend
Jquery.extend = JQuery.fn.extend = function () {var src, copyisarray, copy, name, options, clone, target = Argum Ents[0] | | {},//Common usage jquery.extend (obj1, Obj2), at which point the target is arguments[0] i = 1, length = Arguments.length, D Eep = false; Handle a deep copy situation if (typeof target = = = "Boolean") {//If the first parameter is true, that is, Jquery.extend (true, OBJ1, OB J2); The case of deep = target; At this point target is true target = arguments[1] | | {}; Target change to obj1//Skip the Boolean and the target i = 2; }//Handle case when Target was a string or something (possible in deep copy) if (typeof target!== "Object" && amp;!jquery.isfunction (target)) {//Handle strange situations, such as jquery.extend (' Hello ', {nick: ' Casper}) ~ ~ target = {}; }//Extend JQuery itself if only one argument is passed if (length = = = i) {//handle this case jquery.extend (obj), or Jque Ry.fn.extend (obj) target = this; Jquery.extend, this refers to the Jquery;jquerY.fn.extend, this refers to Jquery.fn-I.; } for (; i < length; i++) {//-deal with non-null/undefined values if (options = arguments[I ]) = null) {//For example Jquery.extend (Obj1, Obj2, Obj3, OJB4), options are Obj2, obj3 ...//Extend the Base object for (name in options) {src = target[name]; copy = options[name]; Prevent never-ending loop if (target = = = copy) {//Prevent self-reference, do not repeat continue; }//Recurse If we ' re merging plain objects or arrays//if it is a deep copy, and the copied property value itself is an object if (deep && copy && jquery.isplainobject (copy) | | (Copyisarray = Jquery.isarray (copy))) {if (Copyisarray) {//copied attribute value is array copyisarray = false; clone = src && jquery.isarray (src)? SRC: []; } else {The property value being copiedis a plainobject, for example {nick: ' casper '} clone = src && jquery.isplainobject (src)? src: {}; }//Never move original objects, clone them target[name] = Jquery.extend (deep, C Lone, copy); Recursive ~//Don ' t bring in undefined values} else if (copy!== undefined) {//Shallow copy, and property value is not u ndefined target[name] = copy; }}}}//Return the modified object return target;
Summarize:
- A new JQuery.fn.init () is used to construct the prototype prototype object with the Init constructor.
- By changing the direction of the Prorotype pointer, the new object also points to the JQuery class's prototype prototype
- So the objects that have been built will continue to jquery.fn all the methods of the prototype definition.
Reprint Aaron Blog----jQuery 2.0.3 Source Analysis Core-Overall architecture