在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
在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 ...
}
其他回答
我不确定最佳实践,但我是这样做的:
/*
* Object Constructor
*/
var foo = function(x) {
this.x = x;
};
/*
* Object Protoype
*/
foo.prototype = {
/*
* f is the name that is going to be used to call the various overloaded versions
*/
f: function() {
/*
* Save 'this' in order to use it inside the overloaded functions
* because there 'this' has a different meaning.
*/
var that = this;
/*
* Define three overloaded functions
*/
var f1 = function(arg1) {
console.log("f1 called with " + arg1);
return arg1 + that.x;
}
var f2 = function(arg1, arg2) {
console.log("f2 called with " + arg1 + " and " + arg2);
return arg1 + arg2 + that.x;
}
var f3 = function(arg1) {
console.log("f3 called with [" + arg1[0] + ", " + arg1[1] + "]");
return arg1[0] + arg1[1];
}
/*
* Use the arguments array-like object to decide which function to execute when calling f(...)
*/
if (arguments.length === 1 && !Array.isArray(arguments[0])) {
return f1(arguments[0]);
} else if (arguments.length === 2) {
return f2(arguments[0], arguments[1]);
} else if (arguments.length === 1 && Array.isArray(arguments[0])) {
return f3(arguments[0]);
}
}
}
/*
* Instantiate an object
*/
var obj = new foo("z");
/*
* Call the overloaded functions using f(...)
*/
console.log(obj.f("x")); // executes f1, returns "xz"
console.log(obj.f("x", "y")); // executes f2, returns "xyz"
console.log(obj.f(["x", "y"])); // executes f3, returns "xy"
由于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对象的示例
如果我需要一个函数与两个使用foo(x)和foo(x,y,z)哪种是最好的/首选的方式?
问题是JavaScript本身不支持方法重载。因此,如果它看到/解析了两个或多个同名的函数,它只会考虑最后定义的函数,并覆盖之前的函数。
我认为适用于大多数情况的一种方法是
假设你有方法
function foo(x)
{
}
而不是重载方法,这在javascript中是不可能的,你可以定义一个新的方法
fooNew(x,y,z)
{
}
然后将第一个函数修改为-
function foo(arguments)
{
if(arguments.length==2)
{
return fooNew(arguments[0], arguments[1]);
}
}
如果你有很多这样的重载方法,考虑使用switch而不是If -else语句。
虽然默认参数没有重载,但它可能解决开发人员在这方面面临的一些问题。输入是严格由顺序决定的,你不能重新排序,因为你希望在经典重载:
function transformer(
firstNumber = 1,
secondNumber = new Date().getFullYear(),
transform = function multiply(firstNumber, secondNumber) {
return firstNumber * secondNumber;
}
) {
return transform(firstNumber, secondNumber);
}
console.info(transformer());
console.info(transformer(8));
console.info(transformer(2, 6));
console.info(transformer(undefined, 65));
function add(firstNumber, secondNumber) {
return firstNumber + secondNumber;
}
console.info(transformer(undefined, undefined, add));
console.info(transformer(3, undefined, add));
结果(2020年):
2020
16160
12
65
2021
2023
更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
我喜欢@AntouanK的方法。我经常发现自己提供了一个具有不同数量参数和不同类型的函数。有时他们不服从命令。我用来映射查找参数类型:
findUDPServers: function(socketProperties, success, error) {
var fqnMap = [];
fqnMap['undefined'] = fqnMap['function'] = function(success, error) {
var socketProperties = {name:'HELLO_SERVER'};
this.searchServers(socketProperties, success, error);
};
fqnMap['object'] = function(socketProperties, success, error) {
var _socketProperties = _.merge({name:'HELLO_SERVER'}, socketProperties || {});
this.searchServers(_socketProperties, success, error);
};
fqnMap[typeof arguments[0]].apply(this, arguments);
}