岁月如歌

用开放的心态,打造专业的人生。

SeaJS – 增加 QueryString 模块

with one comment

给 SeaJS 添加了一个 querystring 模块:

querystring.stringify({foo: 'bar'})
// returns 'foo=bar'

querystring.parse('a=b&b=c')
// returns { a: 'b', b: 'c' }

详细文档:https://github.com/seajs/seajs/tree/master/modules/querystring#readme

主要参考了 node.js 的 querystringYUI3 的 QueryString. 做了一些优化和取舍:

无效百分比编码

node.js 内置的 querystring 最大的特色是重写了 decodeURIComponent. 好处是在遇到无效百分比编码时,不会报错:

querystring.parse('foo=%u0025u96D5');
// node.js: returns { foo: '%u0025u96D5' }
// others: throw URI malformed Error.

但也带来一个问题,不能正确处理非 ASCII 字符:

querystring.parse('foo=雕');
// node.js: returns { foo: '�' }
// others: returns { foo: '雕' }

sea.js 和 YUI3 保持一致,在百分比编码无效时,直接抛异常。

深转换

YUI3 的 QueryString 模块分为 simple 和 normal 两个版本。simple 版本非常简单,normal 版本提供了对对象的深转化:

querystring.stringify({ user: { name: { first: 'Bob' }}});
// YUI3: returns 'user%5Bname%5D%5Bfirst%5D=Bob'
// others: returns 'user='

一旦涉及到对象的深转化,就意味着有可能存在循环依赖。YUI3 的代码里,花了不少功夫来处理循环依赖。

seajs 和 nodejs 一样,未考虑这一情况,毕竟使用场景不多,简单够用就好。

YUI3 还对 number 和 boolean 做了些处理:

querystring.parse('foo=1');
// YUI3: returns { foo: 1 }
// others: returns { foo: '1' }

querystring.stringify({ t: true, f: false });
// YUI3: returns 't=1&f=0'
// others: returns 't=true&f=false'

seajs 和 nodejs 一致,未考虑这些“优化”。简单一致地都转化为字符串类型,对用户来说,或许更符合最小惊讶原则。

hasOwnProperty

这是一个小问题:

querystring.parse('hasOwnProperty=1&toString=2');
// seajs: returns { 'hasOwnProperty': '1', 'toString': '2' }
// others: throws error or returns wrong result.

seajs 里顺手解决了,代价很低。这个 bug 在 underscore 里也存在过,魔鬼隐藏于细节里。

encode 那点事

老话题了,关于 escape, encodeURI 和 encodeURIComponent 的差异请参考测试页面:

encode-compare.html

最后的参考文章很有价值,建议阅读。

在 YUI3, node.js, sea.js, jQuery 等类库的实现里,还有一个不得不提的细节:

querystring.unescape = function(s) {
    // The + character is interpreted as a space on the server side as well as
    // generated by forms with spaces in their fields.
    return decodeURIComponent(s.replace(/\+/g, ' '));
  };

注释里已经说明了原因,留意这个细节就好。

其他类库里的类似功能

jQuery 提供了 param 方法,这其实是一个内部方法,用于 ajax 模块在提交表单字段时的序列化。jQuery 里没有提供 unparam 方法。从这个细节上,可以看出 jQuery 对 DOM 操作的专注,一切与 DOM 关系不大的,都不会添加到 jQuery 中。1.5 中添加的 Deferred Object, 也是因为刚好可以用来改善 ready 的实现方式。jQuery 的这种专注非常难得,希望能继续保持下去。

ExtJS 里,提供了 urlEncode 和 urlDecode 方法,功能大同小异,不多说。

国内前端类库里,KISSY 里提供了 param 和 unparam 方法,Tangram 里提供了 queryToJson 和 json2Query 方法。实现上都还有些细节没到位,不过对于 location.search 的处理来说,足够用了。

小结

写类库很不容易,细节是时间杀手,健壮的类库代码需要整个社区的力量。seajs 本着海纳百川、有容乃大的原则,将尽量筛选出一批质量优异的模块,并回馈给社区。比如给 jQuery 提 bug, 帮助 mustache.js 的作者完善特性,或者像 querystring 一样,在分析现有实现的各种利弊后,重新造一个更好的小轮子。尽量复用他人的成果,同时在某些点上突破,就如博士的图示一样:

什么是博士

在这种模式下,众人拾柴火焰高,很希望你也能参与进来。站在巨人的肩膀上,我们的视野更加辽阔。梦并不遥远,路就在脚下。

Advertisements

Written by lifesinger

May 1, 2011 at 22:22

Posted in Articles

One Response

Subscribe to comments with RSS.

  1. […] https://lifesinger.wordpress.com/2011/05/01/seajs-querystring/ 此条目发表在 未分类 分类目录,贴了 Javascript, Programming, querystring, seajs […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s