在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
JavaScript是一种无类型语言,我认为只有在参数数量方面重载方法/函数才有意义。因此,我建议检查参数是否已经定义:
myFunction = function(a, b, c) {
if (b === undefined && c === undefined ){
// do x...
}
else {
// do y...
}
};
其他回答
这是一个老问题,但我认为需要另一个条目(尽管我怀疑是否有人会读它)。立即调用函数表达式(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。此模式可以重复任意次数,以赋予一个变量若干不同的函数定义。
对于你的用例,这是我用ES6解决它的方法(因为它已经是2017年底了):
const foo = (x, y, z) => {
if (y && z) {
// Do your foo(x, y, z); functionality
return output;
}
// Do your foo(x); functionality
return output;
}
显然,您可以将其用于任何数量的参数,并相应地更改条件语句。
我刚试过了,也许能满足你的需要。 根据参数的数量,您可以访问不同的函数。在第一次调用时初始化它。 函数映射隐藏在闭包中。
TEST = {};
TEST.multiFn = function(){
// function map for our overloads
var fnMap = {};
fnMap[0] = function(){
console.log("nothing here");
return this; // support chaining
}
fnMap[1] = function(arg1){
// CODE here...
console.log("1 arg: "+arg1);
return this;
};
fnMap[2] = function(arg1, arg2){
// CODE here...
console.log("2 args: "+arg1+", "+arg2);
return this;
};
fnMap[3] = function(arg1,arg2,arg3){
// CODE here...
console.log("3 args: "+arg1+", "+arg2+", "+arg3);
return this;
};
console.log("multiFn is now initialized");
// redefine the function using the fnMap in the closure
this.multiFn = function(){
fnMap[arguments.length].apply(this, arguments);
return this;
};
// call the function since this code will only run once
this.multiFn.apply(this, arguments);
return this;
};
测试它。
TEST.multiFn("0")
.multiFn()
.multiFn("0","1","2");
在JS中没有实际的重载,无论如何我们仍然可以用几种方式模拟方法重载:
方法# 1: 使用对象
function test(x,options){
if("a" in options)doSomething();
else if("b" in options)doSomethingElse();
}
test("ok",{a:1});
test("ok",{b:"string"});
方法# 2: 使用rest (spread)参数
function test(x,...p){
if(p[2])console.log("3 params passed"); //or if(typeof p[2]=="string")
else if (p[1])console.log("2 params passed");
else console.log("1 param passed");
}
方法# 3: 使用未定义的
function test(x, y, z){
if(typeof(z)=="undefined")doSomething();
}
方法# 4: 类型检查
function test(x){
if(typeof(x)=="string")console.log("a string passed")
else ...
}
由于JavaScript没有函数重载选项,可以使用对象代替。如果有一个或两个必需的参数,最好将它们与options对象分开。下面是一个关于如何使用options对象和填充值为默认值的例子,如果值没有传递到options对象中。
function optionsObjectTest(x, y, opts) {
opts = opts || {}; // default to an empty options object
var stringValue = opts.stringValue || "string default value";
var boolValue = !!opts.boolValue; // coerces value to boolean with a double negation pattern
var numericValue = opts.numericValue === undefined ? 123 : opts.numericValue;
return "{x:" + x + ", y:" + y + ", stringValue:'" + stringValue + "', boolValue:" + boolValue + ", numericValue:" + numericValue + "}";
}
下面是一个关于如何使用options对象的示例