过眼•物影天狼

博客通天下 淡墨书豪辞

Flower

Archive for the ‘JavaScript’ Category

不要跟 prototype 一起学坏

      新版本的 JSON 修改了 API,将 JSON.stringify() 和 JSON.parse() 两个方法都注入到了 Javascript 的内建对象里面,前者变成了 Object.toJSONString(),而后者变成了 String.parseJSON()。

      不可否认,经过这样的修改,JSON 的接口确实比以前漂亮且好用多了,对于这样的对象:

var obj = new Object;
var arr = new Array();
arr[0] = "a";
arr[1] = "b";
obj["key1"] = arr;
obj["key2"] = "c";

以前的代码得这样写:

var jsonString = JSON.stringify(obj);
var myObj = JSON.parse(jsonString);

而现在的代码是:

var jsonString = obj.toJSONString();
var myObj = jsonString.parseJSON();

      前者 JSON 作为一个工具类,提供一组方法实现转换功能,而后者让你觉得对象天生就具有这样的方法。如果对于编译语言来说,这可能没什么问题,但是对于 Javascript 问题就来了。考虑下面的代码片段:

var obj = new Object(); 
for (var k in obj) {
    document.write(k + "<br>");
}

      如果是一个干净(没有包含任何其他 Javascript 类库)的 Javascript 执行环境,这段代码应该不会输出任何内容,因为 obj 是空的;但是当代码中包含了新版本的 JSON 后,你会发现结果是 toJSONString。很多情况下我们会用 Javascript 的 Object 来模拟 Map,那么上面的这段代码的功能就是遍历此 Map,一个空的 Map 怎么会凭空出来了一个成员?这正是由于新版本的 JSON 的实现所决定的:

Object.prototype.toJSONString = function () {}

      JSON 并不是第一个采用这种写法的 Javascript 类库,始作俑者就是我文章标题中提到的 prototype。prototype 为 Object 注入了 extend 和 instanceof 等方法来支持 Javascript 的面向对象扩展,这样写的后果就是造成了非常严重的兼容性问题。你有没有注意到为什么有些 Javascript 的类库特别声明"使用了 prototype"或者说是"与 prototype 兼容"?因为如果他使用了 prototype 那么你需要在用此类库的时候格外小心,像上面那样的代码不能正常工作;而如果说其与 prototype 兼容,那么可能该类库并没有使用 prototype 但是你使用 prototype 并不会影响他的正常运行。

      prototype 固然是个成功且应用广泛的 Javascript 框架,但是这并不能说明他解决问题的思路就是正确的。开发编译语言程序的人们都知道要以组织或公司的名称作为命名空间前缀,来避免冲突,奈何如此著名的两大 Javascript 框架提供方反而积极去打破这个规则呢?难道实现了功能就可以不考虑兼容性的问题吗?

window.eval() 和 eval() 的却别?

      前两天作了一个试验,把 Javascript 文件当作一个字符串读到浏览器的内存中,然后使用 eval() 方法来解析,对某些内容的 Javascript 文件(我用的是 prototype.js)会有异常抛出。好像浏览器的 Javascript 引擎总是试图去执行一些本来是声名性的语句,例如定义 function。在我的试验中,当解析到 prototype 给 Object 添加的 extend 方法时,说第一个参数 destination 没有定义。

      当研究了另一个非常有名的 Ajax 框架 Dojo 之后发现,如果使用 window.eval() 方法,上面的问题就没有了,解析可以非常顺利地进行,就像把 Javascript 文件通过 <script> 标签引用近来一样。这就产生了一个问题难道 window.eval() 和 eval() 还不一样?

      众所周知,根据 Javascript 规范,其实那些我们经常用到的理解意义上的全局方法,比如 alert(),其实也是有它的依存对象的,这个对象就是 html dom 的 window,也就是说 alert() 就等于 window.alert(),当然 eval() 应该也不例外,但是为什么在这里表现却是如此的不同?

      上网 google 了一下,在这篇文章中找到一点线索,但是仍然不能解决我的疑问。

      文章中说,本来 Javascript(其实他说的是 JScript)应该有两个方法,一个是 eval() 另一个是 execScript()(但是后来在 w3shools 上面却发现 window 只有 execScript() 方法,却没有 eval()!),前者是在函数调用的上下文中执行,就是说如果你在 function myFun() {} 中使用 eval() 那么它就只能访问 myFun 中的成员;而后者是在全局的上下文中执行。文章后面还说到了一些 firefox 相关的问题,但是我发现 ie 的行为在这一点上跟 firefox 是一样的。如果这两个方法仅仅有这点不同的话,那么真的可以像文章中说得那样理解:

  • 如果在函数中使用 window.eval() 来执行,则使用全局上下文环境。
  • 如果使用 eval() 来执行,则使用当前函数的上下文环境。

但是为什么使用函数上下文环境解析就会试图去执行声名性语句呢?

新发现的一个好东西 Script#

      Script# 就是一个用 C# 代码来写脚本语言,然后通过特定的编译器将其转换成 Javascript。

      不想在我这里说太多,作者的 blog 上面已经写的很清楚了。

      有兴趣的可以到这里看一下。

      另外还觉得这个东西生成的 Javascript 所引进的面向对象模型有点意思,等我研究一下再来说说。

You are currently browsing the archives for the JavaScript category.