03 April 2013

原文:ECMAScript 6 and Rest Parameter

在 JavaScript 中处理一个带有可变数目的参数的函数始终是棘手的。至少,我们还有 arguments 对象可以用于获取所有调用函数时的所有参数。随着即将到来的 ECMAScript 6,不再需要这样的技巧,因为我们可以使用它的可变参数功能。

要看清可变参数是如何工作的,请考虑以下情况。你开一辆卡车给杂货店送货。当卸货后,你再把它们入库:

store.add('fruit', 'apple');
store.add('dairy', 'milk', 'cheese', 'yoghurt');
store.add('pastries', 'donuts', 'croissants');

其中 add 是这样实现的:

store.add = function(category) {
  var items = [].slice.call(arguments, 1);
  items.forEach(function (item) {
    store.aisle[category].push(item);
  });
};

请注意,arguments 对象不能被视为一个正常的数组,虽然它的行为总是像一个数组。一个众所周知的伎俩是用 Array.prototype.sliceFunction.prototype.call 作为解决方法,返回第一个参数之后的所有参数列表。

有了可变参数(Section 13.1, ES 6 draft Rev 13),实现要简单的多。它甚至是自解释的。

store.add = function(category, ...items) {
  items.forEach(function (item) {
    store.aisle[category].push(item);
  });
};

可变参数有用的另一个典型的用例是类发布-订阅模式。如果编写基于 Backbone.js 的应用程序,通过 Backbone.Event.trigger 触发事件是一种常见做法。由于一个事件可能需要一个或多个参数,trigger 函数的实现看起来像这样:

trigger: function(name) {
    if (!this._events) return this;
    var args = slice.call(arguments, 1);
    /// ... do something with args ...
    return this;
},

我敢肯定,如果有可变参数功能,你能拿出一个稍有不同的实现。

很显然,如果我们修改 API 以接受一个数组作为第二个参数,就不需要可变参数了。然而在某些情况下,这么做会觉得不太自然。例如,一个字符串格式化程序的实现被期待遵循事实上的 printf format string,而不是把每个参数分组一个简单的数组中。

就像 ECMAScript 6 中的其他语法糖一样,可变参数并没有从根本上改变你编写 JavaScript 代码的方式。但是确实使代码更工具友好,将代码语义解释从运行时行为转移到语法级。一旦编辑器和集成开发环境理解该结构,一个简单的代码提示显示的函数签名足以表名该函数接受一个可变书目的参数。

这太令人兴奋了,不是吗?



blog comments powered by Disqus