前端开发 javascript的链式调用

前端开发 javascrip|前端开发者

1.概念与实现

可链式调用的英文是chainable,我们先看看非chainable是什么样的:
[quote]var object = {
doSomething1: function() {
console.log(‘doSomething1…’);
},
doSomething2: function() {
console.log(‘doSomething2…’);
},
doSomething3: function() {
console.log(‘doSomething3…’);
}
};
object.doSomething1();
object.doSomething2();
object.doSomething3();[/quote]
代码中的最后三行,每次调用都要重复写对象的名称object。
而chainable的代码:

object.doSomething1().doSomething2().doSomething3();
实现的原理,亦很简单,每个方法最后都返回this:
[quote]var object = {
doSomething1: function() {
console.log(‘doSomething1…’);
return this;
},
doSomething2: function() {
console.log(‘doSomething2…’);
return this;
},
doSomething3: function() {
console.log(‘doSomething3…’);
return this;
}
};
object.doSomething1().doSomething2().doSomething3();[/quote]
然而代码都写在一行,是不利于阅读和断点调试的,开发版本中可以格式化一下:
[quote]object
.doSomething1()
.doSomething2()
.doSomething3();[/quote]
说到格式化,如果链的节点返回不是同一个对象,建议使用如下的格式化方式:
[quote]object1
.doSomething1()
.doSomething2()
.getObject2()
.doSomethingElse1();
.doSomethingElse2();[/quote]
尤其是jquery的代码:
[quote]$(‘.container’)
.find(‘p’)
.eq(0)
.removeClass(‘red’)
.css(‘color’, ‘blue’);[/quote]
上面的格式,因人而异吧,有人觉得好看,有人觉得难看。

2.辅助函数
为了链式调用,让我们写代码时,多写几行this,问题倒是不大。
但有的情况是,代码是别人写的,并且对方并没有考虑到所谓i的链式调用。
难道我们只有放弃使用这种优雅的方式了吗?解决方案是有的。

比如有如下的第三方代码:
[quote]function Person(name, age) {
this.name = name;
this.age = age;
this.count++;
}
Person.prototype = {
sayName: function() {
console.log(this.name);
},
sayAge: function() {
console.log(this.age);
},
getCount: function() {
return this.count;
},
count: 0
};
var p = new Person(‘xxx’, 18);
p.sayName();
p.sayAge();
var count = p.getCount();
console.log(count);[/quote]
上面Person类明显是不支持链式调用的。
我们希望的使用方式是:
[quote]var p = new Person(‘xxx’, 18);
var count = p
.sayName()
.sayAge()
.getCount();
console.log(count);[/quote]
要做到链式调用,需要该相应的方法返回this,比如上面的sayName方法。
不改变源代码的基础上,如何让它返回this呢?添加一层包裹函数就能做到,比如:
[quote]var old = Person.prototype.sayName;
Person.prototype.sayName = function() {
var result = old.apply(this, arguments);
return result === undefined ? this : result;
};[/quote]
先执行原方法,根据其返回值,来判断该方法是否支持链式调用。
原sayName是没有返回值的,因此新sayName变成支持链式调用的。
如果把sayName改成getCount,那么新的getCount跟原先做的事情是一样的,仍不支持链式调用的,这是我们想要的结果。

接下来封装个辅助函数:
[quote]function chainablize(constructor) {
var prototype = constructor.prototype;
for (var method in prototype) {
try {
if(prototype.hasOwnProperty(method) && typeof prototype[method] == ‘function’) {
(function(method) {
var old = prototype[method];
prototype[method] = function() {
var result = old.apply(this, arguments);
return result === void 0 ? this : result;
};
})(method);
}
} catch(e) {}
}
}[/quote]
其中使用了try-catch,是因为一些原生对象中的某些属性,使用typeof时会报错。
测试案例如下:
javascript 代码

现在考虑一个问题,如果Person实例是如下的方式使用呢?
[quote]var p = new Person(‘xxx’, 18);
p.name = ‘yyy’;
p.age = 20;
p.sayName();
p.sayAge();[/quote]
对象属性的赋值操作是很常见,
如果赋值操作也能支持链式调用的就好了。
所以有必要发明如下的api,
[quote]p.prop({
name: ‘yyy’,
age: 20
});[/quote]
该api是我们主观添加进去的,第三方的代码可能不提供。
应该长成如下的样子:
[quote]Person.prototype.prop = function(object) {
for (var property in object) {
this[property] = object[property];
}
return this;
}[/quote]
然后我们把它也添加到chainablize函数里:
[quote]function chainablize(constructor) {
var prototype = constructor.prototype;
for (var method in prototype) {
try {
if(prototype.hasOwnProperty(method) && typeof prototype[method] == ‘function’) {
(function(method) {
var old = prototype[method];
prototype[method] = function() {
var result = old.apply(this, arguments);
return result === void 0 ? this : result;
};
})(method);
}
} catch(e) {}
}

if ('prop' in prototype) return;
prototype.prop = function(object) {
    for (var property in object) {
        this[property] = object[property];
    }
    return this;
}

}[/quote]
最终测试案例如下:
javascript 代码

3.案例
这个辅助函数虽然很简单,但其应用相当广。
一、实现canvas链式调用
非链式调用:
html 代码

链式调用:
html 代码

二、实现dom链式操作api
1.非链式调用
html 代码

2.链式调用
html 代码

4.后记
其实本文的思想来源是一个库(chainvas)。库是有点老,不过作者是《css揭秘》的作者。
可以把本文当成其源码分析,其源码没多少,不到200行,看完本文后,照着敲一边应该没问题了。
话说chainablize函数确实修改了内置原型,毕竟为每个方法包裹了一层函数。
但与一般的“猴子补丁”不一样,没有改变原有方法的行为,只是让其尽可能的返回this罢了。
而新增prop确实是“猴子补丁”,可以删除。

前端开发 javascript的链式调用|网站前端开发

https://www.rokub.com

» 本文来自:前端开发者 » 《前端开发 javascript的链式调用》
» 本文链接地址:https://www.rokub.com/2983.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!