多个参数与选项对象

当创build一个带有多个参数的JavaScript函数时,我总是面临这个select:传递一个参数列表与传递一个选项对象。

例如,我正在写一个函数来将一个nodeList映射到一个数组:

function map(nodeList, callback, thisObject, fromIndex, toIndex){ ... } 

我可以使用这个:

 function map(options){ ... } 

选项是一个对象:

 options={ nodeList:..., callback:..., thisObject:..., fromIndex:..., toIndex:... } 

哪一个是推荐的方法? 有什么时候使用一个和另一个的指导方针?

[更新]似乎有一个赞成选项对象的共识,所以我想添加一个评论:为什么我试图使用参数列表在我的情况是一个行为与JavaScript的行为一致内置array.map方法。

像许多其他人一样,我通常更喜欢将一个options object传递给一个函数,而不是传递一长串参数,但是这取决于确切的上下文。

我使用代码可读性作为试金石。

例如,如果我有这个函数调用:

 checkStringLength(inputStr, 10); 

我认为,代码是很可读的方式,并传递个别参数就好了。

另一方面,有这样的调用function:

 initiateTransferProtocol("http", false, 150, 90, null, true, 18); 

完全不可读,除非你做一些研究。 另一方面,这个代码读得很好:

 initiateTransferProtocol({ "protocol": "http", "sync": false, "delayBetweenRetries": 150, "randomVarianceBetweenRetries": 90, "retryCallback": null, "log": true, "maxRetries": 18 }); 

这更像是一门艺术而不是一门科学,但是如果我必须指出经验法则:

使用选项参数如果:

  • 你有四个以上的参数
  • 任何参数都是可选的
  • 你曾经不得不查找函数来找出它需要的参数
  • 如果有人在尖叫“ARRRRRG!”时试图扼杀你

多个参数主要是强制参数。 他们没有错。

如果您有可选参数,则会变得复杂。 如果他们中的一个依靠其他人,以便他们有一个特定的顺序(例如第四个需要第三个),你仍然应该使用多个参数。 几乎所有的本地EcmaScript和DOM方法都是这样工作的。 一个很好的例子是XMLHTTPrequests的open方法 ,其中最后3个参数是可选的 – 规则就像“没有用户没有密码”(另请参阅MDN文档 )。

选项对象在两种情况下派上用场:

  • 你有太多的参数让人困惑:“命名”会帮助你,你不必担心它们的顺序(特别是如果它们可能会改变的话)
  • 你有可选的参数。 对象是非常灵活的,没有任何顺序,你只需传递你需要的东西,没有别的(或undefined的)。

在你的情况下,我build议使用map(nodeList, callback, options)nodelistcallback是必需的,其他三个参数只是偶尔进来,并有合理的默认值。

另一个例子是JSON.stringify 。 你可能想使用space参数而不传递replacer函数 – 那么你必须调用…, null, 4) 。 一个参数对象可能会更好,虽然它只有2个参数并不合理。

使用“选项作为对象”方法将是最好的。 您不必担心属性的顺序,数据传递的灵活性更高(例如可选参数)

创build一个对象也意味着这些选项可以很容易地用于多个function:

 options={ nodeList:..., callback:..., thisObject:..., fromIndex:..., toIndex:... } function1(options){ alert(options.nodeList); } function2(options){ alert(options.fromIndex); } 

我想如果你正在实例化某个东西或调用一个对象的方法,你想使用一个选项对象。 如果它是一个仅用一个或两个参数运行并返回一个值的函数,那么参数列表是最好的。

在某些情况下,使用两者都是好事。 如果你的函数有一个或两个必需的参数和一堆可选的参数,那么首先需要两个参数,第三个参数是一个可选的选项哈希。

在你的例子中,我会做map(nodeList, callback, options) 。 节点列表和callback是必需的,只需通过读取一个调用就可以很容易地知道发生了什么,就像现有的地图function一样。 任何其他选项都可以作为可选的第三个parameter passing。

你对这个问题的评论:

在我的例子中,最后三个是可选的。

那么为什么不这样做呢? (注意:这是相当原始的Javascript。通常我会使用default散列,并使用Object.extend或JQuery.extend或类似的方法传入的选项来更新它。)

 function map(nodeList, callback, options) { options = options || {}; var thisObject = options.thisObject || {}; var fromIndex = options.fromIndex || 0; var toIndex = options.toIndex || 0; } 

所以,现在因为现在更明显什么是可选的,什么不可以,所有这些都是函数的有效用法:

 map(nodeList, callback); map(nodeList, callback, {}); map(nodeList, callback, null); map(nodeList, callback, { thisObject: {some: 'object'}, }); map(nodeList, callback, { toIndex: 100, }); map(nodeList, callback, { thisObject: {some: 'object'}, fromIndex: 0, toIndex: 100, }); 

这取决于。

基于我对这些stream行的库devise的观察,下面是我们应该使用option对象的场景:

  • 参数列表很长(> 4)。
  • 部分或全部参数是可选的,它们不依赖于特定的顺序。
  • 将来的API更新中可能会增加参数列表。
  • API将被其他代码调用,并且API名称不够清楚,无法告诉参数的含义。 所以它可能需要强大的参数名称以提高可读性。

以及使用参数列表的场景:

  • 参数列表很短(<= 4)。
  • 大部分或全部参数是必需的。
  • 可选参数按一定顺序排列。 (即:$ .get)
  • 易于通过API名称来告诉参数的含义。

对象是更可取的,因为如果你传递一个对象,很容易扩展那些对象的属性数量,你不必监视你的parameter passing的顺序。

对于通常使用一些预定义参数的函数,最好使用选项对象。 相反的例子就像是一个函数,获取无限数量的参数,如:setCSS({height:100},{width:200},{background:“#000”})。

我会看大的JavaScript项目。

像谷歌地图的东西,你会经常看到,实例化对象需要一个对象,但function需要参数。 我会认为这与OPTION argumemnts有关。

如果您需要默认参数或可选参数,则对象可能会更好,因为它更灵活。 但是,如果你不正常的function参数是更明确的。

JavaScript也有一个arguments对象。 https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments