• javascript设计模式——链式模式学习


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

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

        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
            }
        }
    

      我们在页面上创建元素

        <div id="aa"></div>
        <div class="cc">1</div>
        <div class="cc">2</div>
    

      js操作

    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一个构造函数。我们试着修改上面的函数

    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源码中是这样的解决这个问题.

    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
        }
    

      让我们来动手试一试!运行效果

            /*单个对象*/
        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设计模式的链式模式的学习喔

  • 相关阅读:
    Windows下快速搭建安卓开发环境android-studio
    使用Android Studio搭建Android集成开发环境
    手动安装配置Android Studio
    android studio 各种问题 应该能帮助到你们
    如何清除XP的网络共享密码
    一个语言的“入流”,而是和这种语言进入某一子行业的契机有关
    必须冷静、必须听话,赶紧走
    QWidget继承自QPaintDevice,这样就可以直接把QWidget传入QPainter的构造函数,比如QPainter(mylabel),然后设置QWidget的长宽后直接进行作画了
    ActiveMQ
    开源word操作组件DocX的记录
  • 原文地址:https://www.cnblogs.com/doudoujs/p/10382427.html
Copyright © 2020-2023  润新知