- 主题:[js] 静态方法链
相对于函数式语言利用返回值不断创建新对象堆叠而成的复杂结构
对象语言的方法链则是针对单一对象进行连续操作的首选方法之一
但有些时候,它的缺陷也是明显的……
为了调用链方法,必须显式地将方法挂为对象的成员;
而为了形成方法链,链方法必须专门被设计成返回对象自身
这样的结构使方法链严格依赖于对象类,从而限制了链方法作为独立工具包存在的可能性
好主意仍然来自于 jquery。
通过使用一个方法而不是一个类对操作对象进行轻量的包装
我们可以直接用对象之外的静态方法形成方法链
所要做的只是保证让操作对象成为链方法的第一个参数:
var setA = function (obj, a) { obj.a = a; };
var setB = function (obj, b) { obj.b = b; };
var sumA = function (obj) { obj.a = obj.a + obj.b; };
var subB = function (obj) { obj.b = obj.a - obj.b; };
var swap = function (obj) { var t = obj.a; obj.a = obj.b; obj.b = t; };
var obj = { a : null, b : null };
$chain(obj)(setA, 1)(setB, 2)(sumA)(subB)(swap);
alert(obj.a + ", " + obj.b); // 1, 3
对值类型的操作则相对麻烦一些……
由于无法通过引用修改原对象,链方法仍然需要返回运算结果:
(注:操作对象不是值类型的话,链方法的返回值将被丢弃)
var trim =
function (str) {
return str.replace(/^\s+/, "").replace(/\s+$/, ""); };
var replace =
function (str, regexp, newSubStr) {
return str.replace(regexp, newSubStr); };
alert($chain(" ABCD ")(trim)(replace, /[B-C]/g, "#")()); // A##D
最后的无参数调用解开包装,并从方法链中取回对象
这使得方法链本身也可以作为参数嵌入到其它的方法调用中
附:包装方法 $chain:
var $chain = function () {
var isPrimitive =
function (obj) {
var t = (typeof obj);
return (obj === undefined || obj === null ||
t == "boolean" || obj instanceof Boolean ||
t == "number" || obj instanceof Number ||
t == "string" || obj instanceof String); };
var link =
function (chain, arguments) {
if (arguments.length === 0) {
return chain.pendant; }
var proc = arguments[0];
var args = [chain.pendant];
for (var i=1; i<arguments.length; i++) {
args.push(arguments[i]); }
var ret = proc.apply(this, args);
if (isPrimitive(chain.pendant)) {
chain.pendant = ret; }
return chain; };
var $chain =
function (obj) {
var chain = function () { return link(chain, arguments); };
chain.pendant = obj;
return chain; };
return $chain; } ();
--
修改:withinsea FROM 221.221.163.26
FROM 221.221.163.26
不是zeze了?^^
【 在 kabbesy (Arthas) 的大作中提到: 】
: orz
--
FROM 221.221.163.26
汗,岂敢……
【 在 pizzaxp (aka 世界上第二可爱的人) 的大作中提到: 】
: 空门大师后继有人了!
--
FROM 221.221.163.26
我自己所有工具方法都不挂在類底下
這個東西對我來講很提高效率的
【 在 modico (modico) 的大作中提到: 】
: 买蛋糕!
: 看起来好像走火入魔了。。。
: 但愿只是在做做练习而已
: ...................
--
FROM 221.221.150.101
你這完全只是不喜歡方法鏈嘛
而且誰說不能調試的……
這個丟給 firebug,斷得很好
var chain = $chain({ a : 0, b : 0 });
chain
(setA, 1)
(setB, 2)
(sumA)
(subB)
(swap);
【 在 modico (modico) 的大作中提到: 】
: 效率?
: 不过是少敲了几个字符。
: 也谈不上运行效率。
: 方法链的写法不利于调试,也就是不利于设断点,死的时候都不知道死在半道哪儿了。
: 不是个好习惯。
--
FROM 221.221.150.101
【 在 roy (天上掉大饼:知行合一) 的大作中提到: 】
: 这个写法和chain.sub().add()……相比好处在什么地方?
: 你为什么prefer这种写法?
不是 prefer,而是不得不這麽寫……
首先一點,我寫這個是爲了用 foo(obj, args..) 這種靜態方法
挂到 obj 類底下寫成 obj.foo(args) 的不算數;
那麽如果我想寫 $chain(obj).foo().bar().... 這樣的話
就必須把所有可能用到的方法挂給 $chain(obj)
但是,既然我無法遍歷臨時變量,那麽這個就是做不到的
所以沒辦法的情況下把 foo,bar 之類都作爲參數傳進去了
: 想不明白啊
: ...................
--
修改:withinsea FROM 221.221.150.101
FROM 221.221.150.101
效率上並不會有什麽區別
我比較喜歡 foo(obj,args) 的原因是爲了讓工具方法能夠獨立出來
擧個典型的例子來講,比如在數組裏面查找一個對象的方法
像 prototype.js 這樣的框架就會實現成這樣:
Array.prototype.find = function (obj) { ...; return idx; };
這樣一來所有數組的成員方法就都變了,因爲它修改了 Array 原型
其結果就是如果我同時使用另一個在 Array 原型上作修改的框架
兩者就很可能發生衝突
另一種實現方法就是寫成比如:
ArrayUtil.find = function (arr, obj) { ...; return idx; };
這種只要 ArrayUtil 這個包對象不重名,各個工具包之間是不會衝突的
而 $chain 的目的就是讓這種形式的工具方法能夠形成方法鏈
【 在 roy (天上掉大饼:知行合一) 的大作中提到: 】
: 为啥非要用静态方法
: obj.foo效率差很多吗?
--
修改:withinsea FROM 221.221.150.101
FROM 221.221.150.101
【 在 roy (天上掉大饼:知行合一) 的大作中提到: 】
: 测试了一下,好像直接函数call比成员函数call要慢
嗯,確實。不過好象影響不大……
: 代码如下:
: <script type="text/javascript">
: ...................
--
FROM 221.221.150.101
不少框架還是很適合混用的嘛。比如 jquery+Ext
好像 dojo 也可以混起來用
【 在 roy (天上掉大饼:知行合一) 的大作中提到: 】
: 恩,不混用框架就好了嘛
: 或者直接用框架提供的扩展机制,比如mootools的object.extend……
這樣的話用過之後還要記得刪
否則啥時候哪裏再來個 for(var-in) 的話又要出問題啦。
hasOwnProperty 也不是哪裏都適用的
--
修改:withinsea FROM 221.221.150.101
FROM 221.221.150.101