JavaScript 现在最令人不爽的就是函数的重载了

2014-05-10 09:52:44 +08:00
 undozen
这还是其他语言里面的概念,JS 里面没有,所以只能自己处理传进来的参数。

比如 superagent 的主入口:


function request(method, url) {
// callback
if ('function' == typeof url) {
return new Request('GET', method).end(url);
}

// url first
if (1 == arguments.length) {
return new Request('GET', method);
}

return new Request(method, url);
}

这里要自己去处理 method 可能传入的是 url,url 可能传入的是 callback 这样的情况。当我要代理这个函数的时候,比如说,给 url 统一加 prefix,我得完全 copy 这个函数!————至少是处理重载的这部分代码。

function uest(method, url) {
var r;

// callback
if ('function' == typeof url) {
r = new request.Request('GET', p(method)).end(url);
}

// url first
else if (1 == arguments.length) {
r = new request.Request('GET', p(method));
}

else r = new Request(method, p(url));

return augment(r);
}

哎~
4144 次点击
所在节点    JavaScript
16 条回复
undozen
2014-05-10 09:58:56 +08:00
类似的情况,tj 的代码中经常会有判断函数的 arity 来给不同反应的,也就是函数对象的 length 属性,也就是说比如

function (a, b, c) {}

定义时括号中指定了三个参数,那么这个函数的 arity 就是三。

tj 代码中常通过 arity 来给不同回调。刚才说到的 superagent,如果回调的 arity ==1 就 callback(response); 如果是 2 或以上,就照 node 的惯例 callback(err, response)

express 中也是,middleware arity 如果是 3 或一下,就是 middleware(req, res, next); 这样,而如果是 4 或以上就说明它是一个处理错误的 middleware,这样去调用 middleware(err, req, res, next)


我觉得根据 arity 来做不同反应真不算是优雅的解决方案。
undozen
2014-05-10 09:59:42 +08:00
以上两个是搞 JS 的时候比较烦的两点。有一些相关性,吐槽一下,也想听听大家的意见。
fundon
2014-05-10 10:24:28 +08:00
这是一个折中方案,要保持public API简单轻量灵活,如果不喜欢这种风格,可以拆出几个public API
ianva
2014-05-10 11:12:29 +08:00
也有很多解决这类问题的库,比如这个 https://github.com/Moeriki/overload-js
之前也想自己整个,但感觉实现起来都不是很优雅
ianva
2014-05-10 11:18:41 +08:00
个人感觉可以自己封装一个,然后用 sweet.js 实现一个自建语法,最后走 grunt 编译,调试走sourcemap,语法校验的话只要别太离谱就ok,这样来到是比较好的解决办法
hitsmaxft
2014-05-10 11:45:39 +08:00
弱类型谈什么重载?

如果需要对参数类型进行匹配, 在函数中进行分发这是常见的做法, 该这么做就这么做.

见 $()
snoopy
2014-05-10 12:49:21 +08:00
@hitsmaxft 我也这么认为
powerfj
2014-05-10 15:55:51 +08:00
有的库的接口这样做是为了保持api的简洁,这样从使用者看来会觉得好像它一个函数啥都能干。然后用的人会觉得简洁,利于库的推广和传播

平常开发的时候参数一多,用对象做参数就ok了,那种代码里面重载的方式我只能说读起来虐心,写起来估计也虐心,尽量少用的好
alsotang
2014-05-10 17:47:52 +08:00
楼主去看看 jquery 的入口函数吧
xcc7624
2014-05-10 20:32:30 +08:00
不能重载有一定原因吧!假如能重载
var foo = function(){};
var foo = function(arg){};
这种定义函数的方式就不行了。
Narcissu5
2014-05-10 23:21:56 +08:00
function request(url,options) {
options = options || {};
var method = options.method || 'GET'
if(options.callback){
return new Request(method,url).end(options.callback);
} else {
return new Request(method,url);
}
}
个人觉得这个函数应该这么写。
这函数,返回的可能end了也可能没有,很糟糕的设计个人觉得
Narcissu5
2014-05-10 23:26:51 +08:00
实际上url这种强制的参数应该放在前面,楼主的这个最大的问题其实就是url可能跑到method上,这样就很乱
cyr1l
2014-05-11 17:03:47 +08:00
所以我建议传参用 Object,

request({
url :"http://google.com",
method:"POST",
callback:callback
})
tamamaxox
2014-05-12 11:12:32 +08:00
js 就是传Object比较好吧,习惯就好
jianv3
2014-05-13 17:05:43 +08:00
函数的重载 可以自己 模拟方法
dcoder
2014-06-16 09:54:10 +08:00
@hitsmaxft 正解,又不是 C++/Java

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/111864

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX