javascript设计模式链式模式学习

  链式模式:经过在对象方法中将当前对象返回,实现对同一个对象多个方法的链式调用。从而简化对该对象的多个方法的屡次调用,对该对象的屡次引用。javascript

  jquery是基于原型继承,每一个原型下的方法都返回当前对象this,让当前对象一直在原型的最高层,这样就能够实现链式调用。咱们来试着建立一个模仿的链式调用的方法.css

var jquery = function(seletor, context) {
        this.init(seletor, context)
    }
    jquery.fn = jquery.prototype = { //简化写法,再写query.prototype就能省点力气直接写jquery.fn
        constructor: jquery,
        length: 0,
        init: function(seletor, context) {
            //定义上下文简化版(*^__^*)
            if (context instanceof jquery) { //判断上下文是不是jquery的实例
                context = context[0]
            } else {
                context = context || document; //指定选择范围
                //判断上下文是否为字符串
                context = typeof context == 'string' ? querySelector(context) || context
            }
            this.context = context; //保存上下文
            if (~seletor.indexOf('#')) { //判断补码是否为0,是则类,反之id选择
                this.length = 1;
                this[0] = context.querySelector(seletor);
            } else { //类选择
                var i = 0,
                    selectArr = context.querySelectorAll(seletor),
                    len = selectArr.length;
                for (; i < len; i++) {
                    this[i] = selectArr[i]
                }
                this.length = len
            }
            return this;
        },
        size: function() {
            return this.length
        }
    }

  咱们在页面上建立元素java

<div id="aa"></div>
    <div class="cc">1</div>
    <div class="cc">2</div>
var $cc = new jquery('#cc');
console.log($cc) //=>jquery {0: div.cc, 1: div.cc, length: 2} 
console.log($cc.size()) //=>2

  可是咱们发现跟真正的jquery有很大差异, 真正的jquery没有显示的new一个构造函数。咱们试着修改上面的函数jquery

var jquery = function(seletor, context) {
  return new jquery.fn.init(seletor, context)
}
//而后执行
var $cc = jquery('#cc');
console.log($cc) //=>jquery {0: div.cc, 1: div.cc, length: 2} 
console.log($cc.size()) //=>$cc.size is not a function

  为何会报错呢?由于这里new jquery.prototype.init,由于这里返回的this指向的是init.prototype,而不是jquery.prototype,init的prototype上并无size这个方法。可是想想,若是new jquery.prototype.init,返回的this指向jquery.prototype,那么不就能调用jquery.prototype的size方法吗?真正的jquery源码中是这样的解决这个问题.ajax

jquery.fn.init.prototype = jquery.fn

  加上这句话再次运行就不会报错啦。
  真正的jquery有许多方法,有直接对jquery对象上挂载方法如:$.ajax,也有对选择器扩展的一些方法,如$(seletor).attr(),$(seletor).css...等等,也有许多jquery上的插件定义的方法。那么咱们如何来拓展呢?在真正的jquery中,若是写过jquery插件或者了解过源码,那么你会知道,是经过extend这个方法来拓展jquery一些方法。咱们来动手试试吧!设计模式

jquery.extend = jquery.fn.extend = function() {
        var i = 1,
            len = arguments.length,
            target = arguments[0], //拷贝的目标对象
            deep, //是否深拷贝标志
            j;
        /*只有一个参数*/
        if (i == len) { //如$.extend({a:1}) 运行后获得$.a =1 
            target = this
            i--
        }
        if (typeof arguments[0] == 'boolean') {
            //若是深拷贝,如$.extend(true,{},{a:1,b:{c:2}},{d:3})
            deep = true
            i == 2
            target = arguments[1] || {}
        }
        for (; i < len; i++) {
            for (j in arguments[i]) {
                var copy = arguments[i][j], //拷贝对象的值
                    src = target[i]; //拷贝到目标对象的值
                var type = {}.toString.call(copy)
                    //深拷贝
                if (deep && (type == '[object Object]' || type == '[object Array]')) {
                    if (!Array.isArray(src)) {
                        src = src || {}
                    } else {
                        src = src || []
                    }
                    target[j] = $.extend(deep, src, copy) //递归循环
                } else if (copy != undefined) {
                    target[j] = copy
                }
            }
        }
        return target
    }

  让咱们来动手试一试!运行效果jquery插件

/*单个对象*/
    var a = {
        a: 1
    }
    jquery.extend(a)
    console.log(jquery.a)
    var b = {
            b: 2,
            c: {
                d: 3
            },
        }
        /*多个对象*/
    var c = jquery.extend(a, b)
    console.log(c)
    c.c.d = 4
    console.log(b.c.d)
    var e = {
            b: 2,
            c: {
                d: 3
            },
        }
        /*深拷贝*/
    var f = jquery.extend(true, a, e)
    f.c.d = 4
    console.log(e.c.d)

  运行成功后咱们来为咱们的jquery添加上方法,click,和attr函数

jquery.fn.extend({
        on: (function(doc) {
            if (doc.addEventListener) {
                return function(type, fn) {
                    var i = this.length - 1
                    for (; i >= 0; i--) {
                        this[i].addEventListener(type, fn, false)
                    }
                    return this
                }
            } else if (doc.attachEvent) {
                return function(type, fn) {
                    var i = this.length - 1;
                    for (; i >= 0; i--) {
                        this[i].attachEvent('on' + type, fn);
                    }
                    return this
                }
            } else {
                return function(type, fn) {
                    var i = this.length - 1;
                    for (; i >= 0; i--) {
                        this[i]['on' + type] = fn
                    }
                    return this
                }
            }
        })(document),
        attr: function() {
            var arg = arguments,
                len = arg.length;
            if (len < 1) return false
            if (len == 1) {
                return this[0].getAttribute(arg[0])
            } else if (len == 2) {
                for (var i in arg[0]) {
                    for (var j = this.length - 1; j >= 0; j--) {
                        this[j].setAttribute(arg[0], arg[1])
                    }
                }
                return this
            }
        }
    })
    jquery('.cc').on('click', function() {
        console.log(this)
    })
    jquery('.cc').attr('class','aa')
    console.log(jquery('.cc').attr('class'))

  以上就是javascript设计模式的链式模式的学习喔。以上皆为demo版jquery代码~学习

相关文章
相关标签/搜索