论坛首页 Web前端技术论坛

JavaScript中链式调用之研习

浏览 11349 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-08-27   最后修改:2011-04-06

 

方法链一般适合对一个对象进行连续操作(集中在一句代码)。一定程度上可以减少代码量,缺点是它占用了函数的返回值。

 

一、方法体内返回对象实例自身(this)

function ClassA(){
	this.prop1 = null;
	this.prop2 = null;
	this.prop3 = null;
}
ClassA.prototype = {
	method1 : function(p1){
		this.prop1 = p1;
		return this;
	},
	method2 : function(p2){
		this.prop2 = p2;
		return this;
	},
	method3 : function(p3){
		this.prop3 = p3;
		return this;
	}
}

 

定义了function/类ClassA。有三个属性/字段prop1,prop2,prop3,三个方法methed1,method2,method3分别设置prop1,prop2,prop3。

链式调用如下:

var obj = new ClassA();
obj.method1(1).method2(2).method(3); // obj -> prop1=1,prop2=2,prop3=3

 

可以看到对obj进行了连续三次操作,只要愿意ClassA的N多方法都这样定义,调用链会一直延续。


该方式缺点是链方法唯一地绑定于一种对象类型(ClaaaA),按这种方式实现链式操作,每定义一个类,其方法体中都要返回this。第二种方式可以解决这个问题。

 

二、对象传入后每次调用返回函数自身

/**
 * chain 精简版
 * @param {Object} obj
 */
function chain(obj){
	return function(){
		var Self = arguments.callee; Self.obj = obj;
		if(arguments.length==0){
			return Self.obj;
		} 
		Self.obj[arguments[0]].apply(Self.obj,[].slice.call(arguments,1));
		return Self;
	}
}

//定义的function/类ClassB
function ClassB(){
	this.prop1 = null;
	this.prop2 = null;
	this.prop3 = null;
}
ClassB.prototype = {
	method1 : function(p1){
		this.prop1 = p1;
	},
	method2 : function(p2){
		this.prop2 = p2;
	},
	method3 : function(p3){
		this.prop3 = p3;
	}
}
 

注意ClassB的method1,method2,method3中不再返回this了。

 

链式调用如下:

var obj = new ClassB();
chain(obj)('method1',4)('method2',5)('method3',6); // obj -> prop1=4,prop2=5,prop3=6

 

第一种方式3次调用后返回了对象自身,这里使用一个空"()"取回对象

// result -> prop1=4,prop2=5,prop3=6
var result = chain(obj)('method1',4)('method2',5)('method3',6)();

 

这种方式写类时方法体中无须返回this,且可以对任何对象进行链式调用。

从写法上总结下两种的调用方式:

obj
	.method1(arg1)
	.method2(arg2)
	.method3(arg3)
	...
	
chain(obj)
	(method1,arg1)
	(method2,arg2)
	(method3,arg3)
	...

 

最后,感谢沐海,我是从wee库中获取以上灵感的。

 

   发表时间:2010-08-27  
呵呵,事实上只要理解了函数调用就是一个表达式,就好理解了
对于高阶函数式编程,执行函数后返回另一个函数(或其自身)是很常见的
0 请登录后投票
   发表时间:2010-08-27   最后修改:2010-08-27
zhouyrt 写道

 

二、对象传入后每次调用返回函数自身

 

/**
 * chain 精简版
 * @param {Object} obj
 */
function chain(obj){
	return function(){
		var Self = arguments.callee; Self.obj = obj;
		if(arguments.length==0){
			return Self.obj;
		} 
		Self.obj[arguments[0]].apply(Self.obj,[].slice.call(arguments,1));
		return Self;
	}
}
 

 

 

第二种方式还是第一次见,很巧妙的用法

 

不过可以简化一下,不使用callee,直接利用闭包:

function chain(obj){
	var fn = function(method){
		if(arguments.length <= 0){
			return fn;
		}
		var args = Array.prototype.slice.call(arguments, 1);
		obj[method].apply(obj, args);
		return fn;
	}
	return fn;
}

 PS:那个[].slice的用法还真是。。。够短,不过总觉得凭白无故创建一个数组只为借它的一个方法用用,有点……

0 请登录后投票
   发表时间:2010-08-27   最后修改:2010-08-27
使用起来能更舒服就好了
例如
var result = chain(obj).method1(4).method2(5).method3(6);
要实现估计要对obj的方法进行重构 还要判断方法本身有没有return
0 请登录后投票
   发表时间:2010-08-27  
cloudgamer 写道
使用起来能更舒服就好了
例如
var result = chain(obj).method1(4).method2(5).method3(6);
要实现估计要对obj的方法进行重构 还要判断方法本身有没有return


谢.
0 请登录后投票
   发表时间:2010-08-27  
第一个还好理解,第二个Self.obj[arguments[0]].apply(Self.obj,[].slice.call(arguments,1));   这句直接看晕了。
0 请登录后投票
   发表时间:2010-08-28  
我在第二种方式上解理起来.....表示压力很大。
我经常用的是第一种。
0 请登录后投票
   发表时间:2010-08-28  
To: clue,tangjikey,ccyingfu

附件中有“易读版”,“最易读版”的chain。
0 请登录后投票
   发表时间:2010-08-28  
这个……理解上有难度。。
0 请登录后投票
   发表时间:2010-08-30  
以前写个一个invoke方法,很是类似于第二个方法,只是一个返回的运算结果,而一个是调用对象callee。
楼主方法在链式调用功能更强大,更适合于无返回参数的运算
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics