在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
因为这篇文章已经包含了很多不同的解决方案,所以我想再发一个。
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
function overload() {
var functions = arguments;
var nroffunctionsarguments = [arguments.length];
for (var i = 0; i < arguments.length; i++) {
nroffunctionsarguments[i] = arguments[i].length;
}
var unique = nroffunctionsarguments.filter(onlyUnique);
if (unique.length === arguments.length) {
return function () {
var indexoffunction = nroffunctionsarguments.indexOf(arguments.length);
return functions[indexoffunction].apply(this, arguments);
}
}
else throw new TypeError("There are multiple functions with the same number of parameters");
}
这可以使用如下所示:
var createVector = overload(
function (length) {
return { x: length / 1.414, y: length / 1.414 };
},
function (a, b) {
return { x: a, y: b };
},
function (a, b,c) {
return { x: a, y: b, z:c};
}
);
console.log(createVector(3, 4));
console.log(createVector(3, 4,5));
console.log(createVector(7.07));
这个解决方案不是完美的,但我只想演示它是如何做到的。
其他回答
因为这篇文章已经包含了很多不同的解决方案,所以我想再发一个。
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
function overload() {
var functions = arguments;
var nroffunctionsarguments = [arguments.length];
for (var i = 0; i < arguments.length; i++) {
nroffunctionsarguments[i] = arguments[i].length;
}
var unique = nroffunctionsarguments.filter(onlyUnique);
if (unique.length === arguments.length) {
return function () {
var indexoffunction = nroffunctionsarguments.indexOf(arguments.length);
return functions[indexoffunction].apply(this, arguments);
}
}
else throw new TypeError("There are multiple functions with the same number of parameters");
}
这可以使用如下所示:
var createVector = overload(
function (length) {
return { x: length / 1.414, y: length / 1.414 };
},
function (a, b) {
return { x: a, y: b };
},
function (a, b,c) {
return { x: a, y: b, z:c};
}
);
console.log(createVector(3, 4));
console.log(createVector(3, 4,5));
console.log(createVector(7.07));
这个解决方案不是完美的,但我只想演示它是如何做到的。
这是一个老问题,但我认为需要另一个条目(尽管我怀疑是否有人会读它)。立即调用函数表达式(IIFE)的使用可以与闭包和内联函数结合使用,以允许函数重载。考虑以下(人为的)例子:
var foo;
// original 'foo' definition
foo = function(a) {
console.log("a: " + a);
}
// define 'foo' to accept two arguments
foo = (function() {
// store a reference to the previous definition of 'foo'
var old = foo;
// use inline function so that you can refer to it internally
return function newFoo(a,b) {
// check that the arguments.length == the number of arguments
// defined for 'newFoo'
if (arguments.length == newFoo.length) {
console.log("a: " + a);
console.log("b: " + b);
// else if 'old' is a function, apply it to the arguments
} else if (({}).toString.call(old) === '[object Function]') {
old.apply(null, arguments);
}
}
})();
foo(1);
> a: 1
foo(1,2);
> a: 1
> b: 2
foo(1,2,3)
> a: 1
简而言之,IIFE的使用创建了一个局部作用域,允许我们定义私有变量old来存储对函数foo的初始定义的引用。这个函数然后返回一个内联函数newFoo,如果传递给它的恰好是两个参数a和b,或者调用旧函数if参数,则该函数将记录两个参数的内容。长度!== 2。此模式可以重复任意次数,以赋予一个变量若干不同的函数定义。
最好的方法取决于函数和参数。你的每个选择在不同的情况下都是一个好主意。我通常按照以下顺序尝试这些方法,直到其中一个有效为止:
Using optional arguments like y = y || 'default'. This is convenient if you can do it, but it may not always work practically, e.g. when 0/null/undefined would be a valid argument. Using number of arguments. Similar to the last option but may work when #1 doesn't work. Checking types of arguments. This can work in some cases where the number of arguments is the same. If you can't reliably determine the types, you may need to use different names. Using different names in the first place. You may need to do this if the other options won't work, aren't practical, or for consistency with other related functions.
用形参重载函数的最好方法不是检查实参长度或类型;检查类型只会让你的代码变慢,你可以享受数组、空值、对象等的乐趣。
大多数开发人员所做的是将一个对象作为方法的最后一个参数。这个物体可以装任何东西。
function foo(a, b, opts) {
// ...
if (opts['test']) { } //if test param exists, do something..
}
foo(1, 2, {"method":"add"});
foo(3, 4, {"test":"equals", "bar":"tree"});
然后你可以在你的方法中任意处理它。[开关,if-else,等等]
第一个选项确实值得注意,因为这是我在相当复杂的代码设置中遇到的问题。所以,我的答案是
一开始就用不同的名字
有一个小但重要的提示,名称应该看起来不同的计算机,但不是你。命名重载函数,如func, func1, func2。