多个参数与选项对象
当创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)
。 nodelist
和callback
是必需的,其他三个参数只是偶尔进来,并有合理的默认值。
另一个例子是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