jQuery source Interpretation ---- part 2

Separator constructor

Construction of an object by the new operator, usually after four steps:

A. Create a new object

B. The scope constructor assigns the new object (so this points to the new object)

C. execution code constructor

D. returns the new object

Finally it shows up, we can just return a new object. In fact, the new operator primarily associating this with the example of the prototype chain up, this is the most crucial point, so we need the prototype chain if the new operator would have to be handled. Otherwise this becomes a window object.

No new format transformation jQuery, we can instanceof to determine whether this is the current instance:

var $$ = ajQuery = function(selector) {
    if(!(this instanceof ajQuery)){ // 第二次看还是觉得这一句很NB
        return new ajQuery(selector);
    }
    this.selector = selector;
    return this
}

But in jQuery actually means is to take an init method on the prototype as a constructor, so the code looks like saving more space?

var $$ = ajQuery = function(selector) {
    //把原型上的init作为构造器
    return new ajQuery.fn.init( selector );
}

ajQuery.fn = ajQuery.prototype = {
    name: 'aaron',
    init: function() {
        console.log(this)
    },
    constructor: ajQuery
}

But it looks like things are also disadvantages, init is on ajQuery prototype as a constructor method, then it is not ajQuery this, so this is completely not ajQuery reference prototype, so here with the init method to separate by new ajQuery into two separate constructor.


Static and instance methods share design

Following the above two questions divided constructor to look at a traversal of interfaces jQuery:

$(".aaron").each()   //作为实例方法存在
$.each()             //作为静态方法存在

Examples appears to require two static methods and functions to implement, but this is jQuery source:

jQuery.prototype = {
    // 调用实例方法实际上是将实例对象this作为一个参数,调用对应的静态方法,这样就形成了共享
    each: function( callback, args ) {
        return jQuery.each( this, callback, args );
    }
}

Examples of Methods in a static method, in other words this is a static and instance methods for sharing design , static methods hung on the jQuery constructor, prototyping hanging where? ------ jQuery as a constructor by init method on the new prototype prototype, then the prototype chain init method is an instance method, so jQuery is divided in two different ways by calling two constructors one is static One is a prototype.

So, if you want to associate the two prototype constructors, the key is to rely on the following sentence:

ajQuery.fn.init.prototype = ajQuery.fn

540905880001daac05540230

Examples of such init constructed objects can be inherited methods on the jQuery prototype.


Implementation of chained calls

JQuery core concept is Write less, Do more (written less, do more), then the method of the chain and the core design philosophy coincide. So deeper consideration of this design is actually a Internal DSL.

DSL refers to the Domain Specific Language, which is used to describe and solve a specific problem areas of language.

The benefits of the Internal DSL jQuery form - when writing code, make the code closer to the author's mode of thinking; when reading the code, make it easier for readers to understand the meaning of the code; DSL applications can effectively improve system maintainability (reduced the realization of distance model and domain model to improve readability) and flexibility of implementation and provides the efficiency of development.

This style duct jQuery DSL chain codes, in general:

☑ saving JS code;

☑ returned are the same object, you can improve the efficiency of the code

Realization of the principle of chaining we know everything, you only need to return in the method of the current instance of the object this can be, because the return this current instance, so that they can access their prototype, and this will save the amount of code improve the efficiency of the code, the code looks more elegant. However, this method has a problem: Method All objects are returned by the object itself, that does not return a value, so this method is not always suitable for any environment.


The plug-in interface design

JQuery plugin development is divided into two types:

One is hung at ☑ jQuery namespace global functions can also be called a static method;

☑ Another method is the level jQuery object, i.e. hang under jQuery prototype method, examples of such jQuery object acquired through the selector which can be shared.

It provides interfaces:

$.extend(target, [object1], [objectN]);
$.fn.extend();

Use interface:

// 拓展到jQuery上的静态方法
jQuery.extend({
    data:function(){},
    removeData:function(){}
})

// 拓展到实例对象上的原型方法
jQuery.fn.extend({
    data:function(){},
    removeData:function(){}
})

The jQuery source code for the above two extensions, in fact, point to the same method with different references (There is a focus on the design, by calling context, we have to determine this is to deal with as a static or instance, of the world total in javascript there are four ways to call context: method call mode, the function call mode, the constructor call mode, apply call mode), and all this is to rely on this to complete.

☑  jQuery.extend调用的时候上下文指向的是jQuery构造器,this指向的是jQuery

☑  jQuery.fn.extend调用的时候上下文指向的是jQuery构造器的实例对象了,this指向实例对象

Therefore, in the source code like this:

aAron.extend = aAron.fn.extend = function() {
    var options, src, copy,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length;

    // 只有一个参数,就是对jQuery自身的扩展处理
    if (i === length) {
        target = this; // 调用的上下文对象,前一个方法对应jQuery,后一个方法对应实例
        i--;
    }
    for (; i < length; i++) {
        // 从i开始取参数,不为空开始遍历
        if ((options = arguments[i]) != null) {
            for (name in options) {
                copy = options[name];
                // 覆盖拷贝
                target[name] = copy;
            }
        }
    }
    return target;
}

Let me explain the code above: Because extend the core functionality is by extending the collection function (similar mix mixed), so it will exist collect objects (target) with data collected since jQuery.extend not really clear parameters, and it is judged by the arguments, so this process it is very flexible. arguments can be overridden by implementing a function of the number of transfer parameters is determined. One of the most important period of target = this, by the way we can really call this current point, so this time will be able to determine the target. Finally, it is simple, through the additional data for looping through to the target on this. Of course, this additional process, we can also do data filtering, and a series of deep copy of the operation.


Back process design

Not only by jQuery DOM object returned after treatment, but a packing container, return the jQuery object. This object has a property of a preObject.

1559366209776

To understand this attribute is what to do, first of all look at the jQuery object stack, internal jQuery jQuery object maintains a stack. Each traversal method (DOM in the current operation of the selected range then screened, e.g. .find () method) will find a new set of elements (a jQuery object), then this group would jQuery element pushed onto the stack.

JQuery and each object has three attributes: context, selector and prevObject (id selector with this attribute is not necessarily the case), which points to prevObject previous object attribute of the object in the stack, and goes back to the property by the initial DOM elements are concentrated.

You can look the following examples:

$("div").find('.foo').find('.aaa') // 这里的preObject属性就会指向$("div").find('.foo')的DOM集合
$("div").find('.foo')  // 往前一级的preObect属性就是指向$("div")的DOM集合

And this mechanism can be traced back to the previously selected set of DOM, for the services of these two methods:

.end() // 回溯到前一个jQuery对象,即prevObject属性
.addBack() // 把当前位置和前一个位置的元素结合组合起来,并且将这个新的组合的元素集推入栈的上方

Backtracking mechanism and utilize the corresponding process can be performed the following operations:

<ul class="first">
    <li class="foo">list item 1</li>
    <li>list item 2</li>
    <li class="bar">list item 3</li>
</ul>

<script>
    // foo类li标签背景设置为红色, bar类li标签背景设置为绿色
    $("#test2").click(function(){
        //通过end连贯处理
        $('ul.first')
            .find('.foo')
            .css('background-color', 'red')
            .end()
            .find('.bar')
            .css('background-color', 'green');
    })
</scripts>

With this DOM element stack can reduce duplication of inquiry and traverse operations, and reduce repetitive operation is also the key to optimize the performance of jQuery code.


end

end approach helps us to backtrack on a DOM collection, so this method is to return a jQuery object, manifested in the source code is returned prevObject objects:

end: function() {
    return this.prevObject || this.constructor(null);
}

So prevObject will produce under what circumstances?

JQuery when building objects by constructing pushStack method, the following code:

pushStack: function( elems ) {
    // Build a new jQuery matched element set
    // 这里将传进来的DOM元素,通过调用jQuery的方法构建成一个新的jQuery对象
    var ret = jQuery.merge( this.constructor(), elems );

    // Add the old object onto the stack (as a reference)
    // 在此对象上把前一个jQuery对象添加到prevObject属性中
    ret.prevObject = this;
    ret.context = this.context;

    // Return the newly-formed element set
    // 最后返回这个jQuery对象
    return ret;
 }

Then find the method, in order to push the stack before a jQuery object, it will call this method to build pushStack:

jQuery.fn.extend({
    find: function(selector) {

        //...........................省略................................

        //通过sizzle选择器,返回结果集
        jQuery.find(selector, self[i], ret);

        // Needed because $( selector, context ) becomes $( context ).find( selector )
        ret = this.pushStack(len > 1 ? jQuery.unique(ret) : ret); // 这里就是将实例对象推入栈中,然后返回新的jQuery对象
        ret.selector = this.selector ? this.selector + " " + selector : selector;
        return ret;
    }
}

Stack and queue operations imitation

Since it is an imitation jQuery array structure, it will certainly achieve a processing method of an array type, such as common operation queue stack push, a series of expansion pop, shift, unshift, summed through the loop each, sorting and screening method.

Providing jQuery .get () ,: index (),: lt () ,: gt () ,: even () and: odd () index value of such associated selector, their effect can be filtered in front of them match expression of a set of elements, is based on the screening of this element in order to match the original collection.

Let's look at the source code to achieve the get method:

get: function(num) {
    return num != null ?  // 不传参为undefined, 走false线
    // Return just the one element from the set
    (num < 0 ? this[num + this.length] : this[num]) :
    // Return all the elements in a clean array
    slice.call(this); // 返回整个DOM元素数组
}

Get the difference and eq

The shoes are well familiar with jQuery, get returns a DOM element, while eq returns the jQuery object, so you can continue chaining.

eq realization of the principle:

eq: function( i ) {
    var len = this.length,
        j = +i + ( i < 0 ? len : 0 );
    return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );

Implement the above logic code is now get the same, the difference is generated by the pushStack a new jQuery object.

If you need is a collection of objects to how to deal with? Thus it provides a slice jQuery method, according to the set of elements having range index, and generate a new jQuery object.

slice method implementation Source:

slice: function() {
    return this.pushStack( slice.apply( this, arguments ) );
},

Iterator

Iterator is important to design a framework. We often desirable to provide a method for processing sequential polymerization of the respective elements of the object, without exposing the interior of the object, which is the design pattern Iterator (Iterator).

For iterators, here are a few features:

☑ access a content aggregation object without having to expose its interior.

☑ provide a unified interface to traverse different sets structure to support the same algorithm operates on a different set of structures.

Change the iterator where ☑ while traversing a set of structures may cause problems.

Also consider these four points:

☑ aggregate object, type of object may be, like a string or array

☑ Support parameter passing

☑ supports passing context

☑ Support loop exits (returns false when the loop exits, saving performance)

Simple implementation of an iterator:

function each(obj, callback, context, arg) {
    var i = 0;
    var value;
    var length = obj.length;
    for (; i < length; i++) {
        value = callback.call(context || null, obj[i], arg);
        if (value === false) {
            break;
        }
    }

jQuery's each iterator

$ .Each () function and $ (selector) .each () is not the same, which is designed to traverse a jQuery object is jQuery internal services.

Examples of static methods jQuery method ultimately calls, we explained before on instances of jQuery and prototype method for sharing design.

$ .Each () Example follows:

// 内部是直接调用的静态方法
each: function(callback, args) {
    return jQuery.each(this, callback, args);
},

jQuery.each static method:

each: function(obj, callback, args) {
    var value,
        i = 0,
        length = obj.length,
        isArray = isArraylike(obj);

    if (args) {
        if (isArray) {
            for (; i < length; i++) {
                value = callback.apply(obj[i], args);

                if (value === false) {
                    break;
                }
            }
        } else {
            for (i in obj) {
                value = callback.apply(obj[i], args);

                if (value === false) {
                    break;
                }
            }
        }

The principle is almost the same, only increased the parameters for judgment. Objects in traversal, traversing the array with for use for.


Guess you like

Origin www.cnblogs.com/simpul/p/11027193.html
Recommended