jQuery源码分析(六): 链式调用与回溯原理

HTML 2016-11-02

起步

链式调用在代码结构上十分清晰,又能简化代码。$("li").eq(1).click().end().eq(3).click();链式调用也体现了jQuery的核心理念Write less,Do more.

链式调用的实现

实现方式说白了是很简单的,学过java,c++,php等面向对象语言的应该都能想到在类的实例方法的末尾return this;将对象返回以便继续调用它的其他方法。

empty: function() {
        list = [];
        firingLength = 0;
        return this;
    },
disable: function() {
        list = stack = memory = undefined;
        return this;
    },

我们在程序设计的时候,也可以通过简单的return this;来实现链式,不仅节省代码,而且提高效率,代码也更优雅。但由于返回是对象本身,就不会有其他返回值了,所以这种方法还是根据场景来使用。

回溯原理

jq中end()的源码中:

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

在jQuery对象中有个prevObject对象,这是在什么地方的?它的产生其实是在对象产生中放到栈里的时候赋值的:

pushStack: function( elems ) {
    var ret = jQuery.merge( this.constructor(), elems );

    ret.prevObject = this;
    ret.context = this.context;
    return ret;
},

jq内部维护这一个jq对象栈,是放jq对象的不是dom对象。而每个jq对象都有三个属性:contextselectorprevObject,其中的prevObject属性就指向这个对象栈中的前一个对象,通过这种回溯可以找到最初的对象。

带过滤功能的回溯

jquery总共提供了两个方法进行回溯操作:.end() .addBack(),end()是简单返回栈中最后一个对象,而addBack()可以对栈中对象进行过滤,返回一个或一批对象的集合,它是一个选择性的过滤器:

addBack: function( selector ) {
        return this.add( selector == null ?
        this.prevObject : this.prevObject.filter(selector)
    );
}

add: function( selector, context ) {
        return this.pushStack(
            jQuery.unique(
                jQuery.merge( this.get(), jQuery( selector, context ) )
                )
            );
},

从源码中可以看到,使用addBack()会把过滤出来的新的、组合之后的元素集推入栈的上方,这也是它与end()的一个不同。

部分API上可能写的是andSelf()。其实他们是一样的。

jQuery.fn.andSelf = jQuery.fn.addBack;

andSelf()只是它的一个别名,这是因为低版本用andSelf(),这是为了兼容,在高版本中应使用addBack()

总结

通过栈和记录前一个对象的方式实现回溯,可以减少重复的查询,或者是在一个较小的范围内进行操作。end()获得了前一个jq对象,addBack()则是可以回溯到栈的某个对象或多个对象,并把他们这成新的jq对象放入栈顶。


本文由 hongweipeng 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

赏个馒头吧