shim是应该抛异常还是应该fail silently?
玉伯发布了es5-safe模块,这是一个有一点类似es5-shim的项目。
个人认为玉伯这个模块对于准备从ES3过渡到ES5的前端开发者来说是一个稳妥的选择。在本文的最后部分会进一步说明。下面的部分是理论性的探讨,无兴趣者可略过了。
es5-safe的缘起,是玉伯主张一个不太一样的策略,即“用 throw error 的策略来代替 fail silently”。
玉伯在《扩展原生对象与 es5-safe 模块》一文中写道:
obj.bar = 2;var foo = obj.foo;var bar = obj.bar;if(foo !== 2) foo = 2;if(bar === undefined) alert('fu*ck');
这样会让使用者发狂的。
要么完美支持,要么抛出异常,灰色地带很诱人但实在危险。基础类库的 fail silently,要做到无害,无隐患(ES5 的这些方法里好像没有)很难。
2 楼 hax 2011-08-12 @lifesinger
你的例子当中,create一个带有get accessor的对象。如我文中所述,es5-shim对此也是抛出异常的,尽管其文档说是fail silently。因此在这点上已经可以起到提示开发者的作用。
而我说seal这个防御性调用,通常fail silently是可接受的,这个前提是我们使用ES5 strict模式(也许我文中还不够强调此点)。
在strict模式下, obj.bar = 2 会扔出TypeError。因此不用到IE6里我们就已经发现错误了。
因此也不会有你所说的类库使用者调整代码的必要了。
唯一可能导致错误的情形是代码依赖于此种异常,如:
try {
obj.bar = 2
} catch(e) {
// do sth...
}
我很难想到一个合理的case,需要这样的代码。
即使真的有这样的需求,也很容易将捕捉异常改为测试方法:
if (Object.seal(obj) {
// do sth...
}
总之,es5-shim的目标并非要“完美”支持,而是让在ES5环境里可以跑的程序也能不做改动跑在前es5环境中。
凡是真的无法运行在IE6中的,那在IE6中扔出异常是应该的。例如get/set。而seal这类防御性代码,在正常情形下,是不会影响代码逻辑的,因此fail silently是可接受的。当然我们可能犯错,所以我建议始终用strict模式,这样在FF调试时你已经能发现错误(比如对sealed对象的修改),这样这个bug就不会留到IE6中去。
如果开发者故意选择了non-strict模式,或者其代码依赖于对防御性代码的功能性运用(如利用try/catch),那他应该明确了解他在干什么,并承担后果,呵呵。
【也许我应将本文改写为《es5-shim最佳实践》?呵呵】
3 楼 hax 2011-08-12 另外,如果遵循了我所说的采用strict模式,并且不做“功能性的利用防御性方法”这样奇怪的事情,那么要兼容IE6所要记住的东西其实还挺少的。就是以下两点:
1. 不要用get/set
2. 不要依赖enumerable
其中第二点在未来可能会得到解决。
其他的坑基本上在strict模式下已经都填平了。不会漏到IE6那里去。
【当然坑总是有的,如lifesinger原文中提到的array literal initialization的坑,不过这种坑不是es5-shim或es5-safe可以解决的。】 4 楼 lifesinger 2011-08-12 明白了,我测试时忘了打开 strict 模式
就怕这种忘了导致的 bug, 特别是大团队合作时
我还是继续 es5-safe 先
等 ie6-7 可以不考虑了,再切换到 es5-shim, ie8 下貌似绝大部分都可以“安全”实现 5 楼 hax 2011-08-15 lifesinger 写道明白了,我测试时忘了打开 strict 模式
就怕这种忘了导致的 bug, 特别是大团队合作时
确实,这里存在这种可能。除了“忘记”之外,还有一点就是目前浏览器的stable版本支持strict的并不多,如chrome/safari目前的stable版本尚不支持strict模式。NodeJS stable版本(0.4.x)也不支持strict模式。
所以目前要测试时,除了加上"use strict"外,还必须是在以下环境:
FF 4+
Chrome/Safari的beta版
NodeJS 0.5+