无限调用之链模式分析
栏目: JavaScript · 发布时间: 5年前
内容简介:链模式相信大家很常见,尤其在jq中,我们非常习惯的可以使用jq的链式模式中连续的进行方法的调用,虽然我们知道其在方法执行后会返回this的当前对象,来实现这个模式的设计,我们还是进行更加详细的研究学习吧。首先我们知道的是链模式是基于原型,比如我们在假设我们的方法为A。我们现在的方法和属性都是定义在原型链上,a本身是方法,我们通过实例化方法可以访问到原型链上的方法。但是这样是有问题的,我们知道jq的方式是直接用返回对象并没有实例化的方法,那我们可以进行借助另一个对象来实现。
链模式相信大家很常见,尤其在jq中,我们非常习惯的可以使用jq的链式模式中连续的进行方法的调用,虽然我们知道其在方法执行后会返回this的当前对象,来实现这个模式的设计,我们还是进行更加详细的研究学习吧。
基于原型的继承
首先我们知道的是链模式是基于原型,比如我们在假设我们的方法为A。我们现在的方法和属性都是定义在原型链上,a本身是方法,我们通过实例化方法可以访问到原型链上的方法。
function A (){} A.prototype = { length:2, size:function(){ return this.length } } let a = new A() console.log(a.size()) //2 // 没有size 是因为方法定义在原型链上 console.log(A.size()) // 没有size执行是因为a方法的执行没有任何返回值 console.log(A().size()) 复制代码
但是这样是有问题的,我们知道jq的方式是直接用返回对象并没有实例化的方法,那我们可以进行借助另一个对象来实现。
借助助手
我们可以借助另外的对象进行,上面讲到A().size()不行是因为a方法没有任何任何值,那么我们可以进行返回。如下的方式改造就可以直接a方法调用函数了。
function A (){ return B } let B = A.prototype = { length:2, size:function(){ return this.length } } console.log(A().size()) //2 // 为了减少变量的创建,我们直接用A的属性来承接 A.fn = A.prototype = { length:2, size:function(){ return this.length } } 复制代码
获取元素
我们知道jq最终是为了获取元素的集合,所以目前的方式肯定是不合适的。所以我们需要在原型对象上定义一个init方法来获取对象。那么我们需要在A方法执行的时候直接返回我们的初始化方法。
function A (seletor){ return A.fn.init(seletor) } A.fn = A.prototype = { init:function(seletor){ return document.getElementById(seletor) }, length:2, size:function(){ return this.length } } console.log(A("demo")) // dom 复制代码
返回我们需要的方法
虽然之前的设计可以得到元素了,但这样的元素不具有我们想要的方法,那么如何让返回的元素具有我们想要的方法呢,在方法体重我们可以看到A.fn是具有我们的方法的。
function A (seletor){ return A.fn.init(seletor) } A.fn = A.prototype = { init:function(seletor){ this[0] = document.getElementById(seletor) this.length = 1 return this }, length:2, size:function(){ return this.length } } console.log(A("demo").size()) // 1 得到校验后的长度 复制代码
此时发现另外的问题了,就是我们进行另外一个元素的使用时,元素会互相覆盖,原因是因为我们每次都是返回利用的同一个对象。
覆盖获取
解决覆盖获取的方式也很简单,恢复实例化即可。但这样也会导致方法无法使用。报错如下: A(...).size is not a function
function A (seletor){ return new A.fn.init(seletor) } 复制代码
方法丢失
原因是因为前者返回的是当前对象,也就是A.fn和A.prototype,但如果是new的进行的是属性的复制,与前面不同。
经过测试,init方法中第一种方式返回的确实是a.fn,a.prototype,而如果是返回new a.fn.init,那么返回的是a.fn.a.init
jq的解决方案
直接将a.fn的原型指向存在的对象即可。
A.fn.init.prototype = A.fn 复制代码
这样就可以满足我们的基本需求了。
丰富的元素获取
上面的代码可以实现获取id元素的标签,但实际上我们有各种可能,这种时候只要判断选择器的内容,然后针对性的获取元素就好。
init:function(selector,context){ this.length = 0 context = context || document if(~selector.indexOf("#")>-1){ this[0] = document.getElementById(selector.slice(1)) this.length = 1 } ... } 复制代码
数组与对象
虽然我们实现了基本的方法,但发现仍然存在一个使用上的特性,就是jq的元素支持数组的很多操作,为了让我们的返回对象也具有类似的功能,我们需要在原型链上追加push\sort\split等类似数组的方法来实现。
A.fn = A.prototype = { // 数组方法添加 增强数组特性 push:[].push, sort:[].sort, splice:[].splice } 复制代码
方法拓展extend
A.extend = A.fn.extend = function(){ var i = 1,len = arguments.length, target = arguments[0] if(i === len){ target = this ; i-- } for(;i<len; i++){ for(j in arguments[i]){ target[j] = arguments[i][j] } } return target ; } 复制代码
添加方法,返回this
所以如果你要添加方法,你直接用就可以。
A.fn.extend = ({ html:function(){ var arg = arguments,len = arguments.length; if(len === 0){ return this[0] && this[0].innerHtml; } else { for(var i = this.length -1 ; i >=0 ; i-- ){ this[i].innerHtml = arg[0] } } // 返回this 支持链式调用 return this } }) 复制代码
以上所述就是小编给大家介绍的《无限调用之链模式分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- [Golang 游戏leaf系列(五) chanrpc三种调用模式
- 直观讲解-RPC调用和HTTP调用的区别
- 调用链系列一:解读UAVStack中的调用链技术
- 调用链系列二:解读UAVStack中的调用链技术
- 调用链系列三:解读UAVStack中的调用链技术
- dubbo源码解析(二十七)远程调用——injvm本地调用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。