链式调用的优点是代码简洁易读,减少了多次重复使用同一个变量。最常见的还是在jQuery库里面,例如:
$(‘#id’).show().hide().show().hide().show().hide();
(当然,这么调用纯属蛋疼)
在上面的语句中,$(‘#id’)是一个对象,然后链式的执行方法,其中的原理很简单,就是执行完一个方法之后就返回本身(return this);然后被返回的对象(上例中就是$(‘#id’))继续执行后面的方法,如果你这么写:
var obj = $(‘#id’).show().hide().show().hide().show().hide();
再看obj,他还是 $(‘#id’)这货,就像var obj = function(){ return this;}一样;
现在我们要想了,可不可以这么调用:
document.getElementById(‘id’).show().hide().show().hide().show();
由于document.getElementById(‘id’);返回的是一个对象,初始并不含有show()和hide()方法,可见,既然jquery里面可以这么调用,$(‘#id’)返回的肯定也不是浏览器的原生对象,是经过扩展以后的jquery对象。
如果我们想如上面那么调用,我们可以扩展Object对象:
Object.prototype.show = function(){
console.log('show');
return this;
}
Object.prototype.hide = function(){
console.log('hide');
return this;
}
当然这种方法并不明智,程序里面还是尽量不要修改原生类型的原型(如果代码完全可控,另当别论),所以比较好的处理方法是自定义一个对象,然后包装此对象,把方法挂在其上(即jquery采取的方案)。
下面是比较简陋的一个示例:
window.$ = function(id){
return new _$(id);
}
function _$(id){
this.elements = document.getElementById(id);
}
_$.prototype = {
constructor:_$,
hide:function(){
console.log('hide');
return this;
},
show:function(){
console.log('show');
return this;
}
}
$('id').show().hide().show().hide().show();
$('id')返回的是经过包装的对象,于是就可以实现链式调用了。
这样有点不爽就是可能方法很多,对象很臃肿。
另外有一点要说明的就是像上面链式调用的一个不好使的地方是,链式调用比较适合赋值器方法,不适合取值器方法,为了保持链式调用的统一,可以用回调函数来处理取到的值,我们扩展一下上面的示例:
window.$ = function(id){
return new _$(id);
}
function _$(id){
this.elements = document.getElementById(id);
}
_$.prototype = {
constructor:_$,
hide:function(){
console.log('hide');
return this;
},
show:function(){
console.log('show');
return this;
},
getName:function(callback){
if(callback){
callback.call(this,this.name);
}
return this;
},
setName:function(name){
this.name = name;
return this;
}
}
$('id').setName('xesam').getName(function(name){
console.log(name);
}).show().hide().show().hide().show();
链式操作没有中断,但是可以获得返回的值。
其实个人感觉这么取值调用不是很直观,所以jQuery里面这样的也没怎么用。原理还是很简单的,有什么补充的以后再加。
参考资料:《javascript设计模式》
书评:这本书感觉有些难度,纯粹的JS模式分析,重在参悟。对新手或者没有其他编程经验的人来说理解会比较难受一点,不过要成长,这总是必经的一步。