Home > Web Front-end > JS Tutorial > jQuery 2.0.3 source code analysis core (1) overall architecture_jquery

jQuery 2.0.3 source code analysis core (1) overall architecture_jquery

WBOY
Release: 2016-05-16 16:46:40
Original
1076 people have browsed it

When you read about an open source framework, what you want to learn most is the design ideas and implementation techniques.

Not much nonsense, jquery analysis has been bad for so many years, I have read it a long time ago,

However, in the past few years, I have been working on mobile terminals and have always used zepto. Recently, I took some time to scan jquery again

I will not translate the source code according to the script, so please read it based on your own actual experience!

The latest one on github is jquery-master, which has joined the AMD specification. I will refer to the official latest 2.0.3

Overall structure

The core of the jQuery framework is to match elements from HTML documents and perform operations on them,

For example:

Copy code The code is as follows:

$().find().css()
$().hide().html('....').hide().

At least 2 problems can be found from the above writing

1. How jQuery objects are constructed

2. How to call jQuery method

Analysis 1: jQuery’s new-free construction

JavaScript is a functional language. Functions can implement classes. Classes are the most basic concept in object-oriented programming

Copy code The code is as follows:

var aQuery = function(selector, context) {
//Constructor
}
aQuery.prototype = {
//Prototype
name:function(){},
age:function(){}
}

var a = new aQuery();

a.name();

This is a conventional usage method. It is obvious that jQuery does not work this way

jQuery does not use the new operator to instantiate jQuery display, or directly calls its function

Follow the writing method of jQuery

Copy code The code is as follows:

$().ready()
$( ).noConflict()

To achieve this, jQuery must be regarded as a class, then $() should return an instance of the class

So change the code:

Copy code The code is as follows:

var aQuery = function(selector, context) {
Return new aQuery();
}
aQuery.prototype = {
name:function(){},
age:function(){}
}

Through new aQuery(), although an instance is returned, we can still see an obvious problem, an infinite loop!

So how to return a correct instance?

Instance this in javascript is only related to the prototype

Then you can use the jQuery class as a factory method to create instances, and put this method in the jQuery.prototye prototype

Copy code The code is as follows:

var aQuery = function(selector, context) {
Return aQuery.prototype.init();
}
aQuery.prototype = {
init:function(){
return this;
}
name:function(){ },
age:function(){}
}

Instance returned when aQuery() is executed:

Obviously aQuery() returns an instance of the aQuery class, so this in init actually points to an instance of the aQuery class

The problem is that this in init points to the aQuery class. If the init function is also used as a constructor, how to deal with the internal this?

Copy code The code is as follows:

var aQuery = function(selector, context) {
Return aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
name: function() {},
age: 20
}

aQuery().age //18

In this case, something goes wrong, because this only points to the aQuery class, so you need to design an independent scope

JQuery framework separate scope processing

Copy code The code is as follows:

jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},

Obviously, through the instance init function, a new init instance object is constructed every time to separate this and avoid interaction confusion

So since they are not the same object, a new problem must arise

For example:

Copy code The code is as follows:

var aQuery = function(selector, context) {
Return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
} ,
name: function() {},
age: 20
}

//Uncaught TypeError: Object [object Object] has no method 'name'
console.log(aQuery().name())

An error is thrown and this method cannot be found, so it is obvious that the init of new is separated from this of the jquery class

How to access the properties and methods on the jQuery class prototype?

How can we not only isolate the scope but also use the scope of the jQuery prototype object? Can we also access the jQuery prototype object in the returned instance?

Key points of implementation

Copy code The code is as follows:

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

Solve the problem through prototype passing, pass the jQuery prototype to jQuery.prototype.init.prototype

In other words, jQuery’s prototype object overrides the prototype object of the init constructor

Because it is passed by reference, there is no need to worry about the performance issue of this circular reference

Copy code The code is as follows:

var aQuery = function(selector, context) {
Return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
return this;
},
name: function( ) {
return this.age
},
age: 20
}
aQuery.prototype.init.prototype = aQuery.prototype;
console.log(aQuery(). name()) //20

Baidu borrowed a picture from a netizen for easy and direct understanding:

Explain fn, in fact, this fn has no special meaning, it is just a reference to jQuery.prototype

Analysis 2: Chain Call

Handling of DOM chain calls:

1. Save JS code.

2. The same object is returned, which can improve the efficiency of the code

Achieve cross-browser chain calls by simply extending the prototype method and returning this.

Use the simple factory pattern under JS to specify the same instance for all operations on the same DOM object.

This principle is super simple

Copy code The code is as follows:

aQuery().init().name()
Decompose
a = aQuery();
a.init()
a.name()

Breaking down the code, it is obvious that the basic condition for realizing chaining is the existence of instance this, and it is the same

Copy code The code is as follows:

aQuery.prototype = {
init: function( ) {
return this;
},
name: function() {
return this
}
}

So we only need to access this in a chained method, because it returns this of the current instance, so we can access our own prototype

Copy code The code is as follows:

aQuery.init().name()

Advantages: save the amount of code, improve the efficiency of the code, and the code looks more elegant

The worst thing is that all object methods return the object itself, which means there is no return value, which may not be suitable in any environment.

Javascript is a non-blocking language, so it is not blocking, but it cannot block, so it needs to be driven by events and asynchronously complete some operations that need to block the process. This processing is only a synchronous chain, and an asynchronous chain jquery Promise has been introduced since 1.5, and jQuery.Deferred will be discussed later.

Analysis 3: Plug-in interface

The main framework of jQuery is like this, but according to the general designer's habits, if you want to add attribute methods to jQuery or jQuery prototype, and if you want to provide developers with method extensions, should they be provided from the perspective of encapsulation? An interface is the right one, and it can be understood literally that it is an extension of the function, rather than directly modifying the prototype. Friendly user interface,

jQuery supports its own extended properties. This provides an external interface, jQuery.fn.extend(), to add methods to objects

As you can see from the jQuery source code, jQuery.extend and jQuery.fn.extend are actually different references pointing to the same method

Copy code The code is as follows:

jQuery.extend = jQuery.fn.extend = function( ) {

jQuery.extend extends the properties and methods of jQuery itself

jQuery.fn.extend extends the properties and methods of jQuery.fn

The extend() function can be used to easily and quickly extend functions without destroying jQuery’s prototype structure

jQuery.extend = jQuery.fn.extend = function(){...}; This is consecutive, that is, two points pointing to the same function, how can they achieve different functions? This is the power of this!

Fn and jQuery are actually two different objects, as described before:

When jQuery.extend is called, this points to the jQuery object (jQuery is a function and an object!), so the extension here is 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 extending fn is to extend the jQuery.prototype prototype object.
What is added here is the prototype method, which is the object method. Therefore, the jQuery API provides the above two extension functions.

Implementation of extend

Copy code The code is as follows:

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},    // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
        deep = target;  // 此时target是true
        target = arguments[1] || {};    // target改为 obj1
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {    // 防止自引用,不赘述
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 如果是深拷贝,且被拷贝的属性值本身是个对象
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷贝的属性值是个数组
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

// NEVER MOVE Original Objects, Clone Them
Target [name] = jquery.extEnd (deep, clone, copy); // Recursive ~

                                                                                                                                                                                         }
}
}
}

// Return the modified object
return target;



Summary:

Construct a new object through new jQuery.fn.init(), with the prototype prototype object method of the init constructor

By changing the pointing of the prototype pointer, let this new object also point to the prototype of the jQuery class prototype

So the object constructed in this way continues all the methods defined by jQuery.fn prototype

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template