谨慎使用YAHOO.lang.substitute
这个方法很好很强大,看代码:
function println(msg) { document.write((msg ? msg : '') + '<br />'); }
var s = '名称:{name}, 数量:{num}, 描叙:{desc}';
var o = { name: 'iPhone 3G', num: '8', desc: '很好' };
var r = YAHOO.lang.substitute(s, o);
println(r); // => 名称:iPhone 3G, 数量:8, 描叙:很好
注意o.desc的值可以包含各种字符,比如:
var s = '名称:{name}, 数量:{num}, 描叙:{desc}';
var o = { name: 'iPhone 3G', num: '8', desc: '{name}很好' };
var r = YAHOO.lang.substitute(s, o);
println(r); // => 名称:iPhone 3G, 数量:8, 描叙:iPhone 3G很好
可以发现,substitute方法会循环替换所有{key},这就产生了隐患:
var s = '名称:{name}, 数量:{num}, 描叙:{desc}';
var o = { name: 'iPhone 3G', num: '8', desc: '{desc}很好' };
var r = YAHOO.lang.substitute(s, o);
println(r); // => 恐怖的死循环
上面是发生在淘宝上的一个真实案例。我们的本意是只想替换一层,但substitute方法的递归导致了淘宝的list页面在某些特定情况下会陷入恐怖的死循环。知道了原因,解决办法就简单了。substitute支持第三个参数:
var s = '名称:{name}, 数量:{num}, 描叙:{desc}';
var o = { name: 'iPhone 3G', num: '8', desc: '{desc}很好' };
var r = YAHOO.lang.substitute(s, o, function(k, v) {
v = v ? v : '';
if(v.indexOf('{' + k + '}') >= 0) {
v = v.replace('{', '{');
v = v.replace('}', '}');
}
return v;
});
println(r); // => 名称:iPhone 3G, 数量:8, 描叙:{desc}很好
测试,一切工作得很好,不用担心死循环了。
…
若干天后,突然某个页面,运营部风急火燎的说又出错了:

检查数据,发现num少了引号:
var o = { name: 'iPhone 3G', num: 8, desc: '{desc}很好' };
没有引号导致num被解析成Number, 自然没有indexOf属性了。狂汗,立改之:
var s = '名称:{name}, 数量:{num}, 描叙:{desc}';
var o = { name: 'iPhone 3G', num: 8, desc: '{desc}很好' };
var r = YAHOO.lang.substitute(s, o, function(k, v) {
v = String(v ? v : '');
if(v.indexOf('{' + k + '}') >= 0) {
v = v.replace('{', '{');
v = v.replace('}', '}');
}
return v;
});
println(r); // => 名称:iPhone 3G, 数量:8, 描叙:{desc}很好
至此,终于风停雨消,可以安心睡觉了-.-
附上测试页面:yui_substitute_test.html

October 6th, 2008 on 19:08
为什么会出现死循环呢?
October 6th, 2008 on 21:19
死循环是因为YUI的源码里,
substitute: function (s, o, f) { ... for(;;) { ... s = s.substring(0, i) + v + s.substring(j + 1); } ... }leave a reply