在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
你可以使用John Resig的addMethod。使用此方法,您可以根据参数计数“重载”方法。
// addMethod - By John Resig (MIT Licensed)
function addMethod(object, name, fn){
var old = object[ name ];
object[ name ] = function(){
if ( fn.length == arguments.length )
return fn.apply( this, arguments );
else if ( typeof old == 'function' )
return old.apply( this, arguments );
};
}
我还创建了该方法的替代方法,使用缓存来保存函数的变体。这里描述了不同之处
// addMethod - By Stavros Ioannidis
function addMethod(obj, name, fn) {
obj[name] = obj[name] || function() {
// get the cached method with arguments.length arguments
var method = obj[name].cache[arguments.length];
// if method exists call it
if ( !! method)
return method.apply(this, arguments);
else throw new Error("Wrong number of arguments");
};
// initialize obj[name].cache
obj[name].cache = obj[name].cache || {};
// Check if a method with the same number of arguments exists
if ( !! obj[name].cache[fn.length])
throw new Error("Cannot define multiple '" + name +
"' methods with the same number of arguments!");
// cache the method with fn.length arguments
obj[name].cache[fn.length] = function() {
return fn.apply(this, arguments);
};
}
其他回答
我经常这样做:
C#:
public string CatStrings(string p1) {return p1;}
public string CatStrings(string p1, int p2) {return p1+p2.ToString();}
public string CatStrings(string p1, int p2, bool p3) {return p1+p2.ToString()+p3.ToString();}
CatStrings("one"); // result = one
CatStrings("one",2); // result = one2
CatStrings("one",2,true); // result = one2true
JavaScript相当于:
function CatStrings(p1, p2, p3)
{
var s = p1;
if(typeof p2 !== "undefined") {s += p2;}
if(typeof p3 !== "undefined") {s += p3;}
return s;
};
CatStrings("one"); // result = one
CatStrings("one",2); // result = one2
CatStrings("one",2,true); // result = one2true
This particular example is actually more elegant in javascript than C#. Parameters which are not specified are 'undefined' in javascript, which evaluates to false in an if statement. However, the function definition does not convey the information that p2 and p3 are optional. If you need a lot of overloading, jQuery has decided to use an object as the parameter, for example, jQuery.ajax(options). I agree with them that this is the most powerful and clearly documentable approach to overloading, but I rarely need more than one or two quick optional parameters.
编辑:根据Ian的建议更改IF测试
在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 ...
}
最好的方法取决于函数和参数。你的每个选择在不同的情况下都是一个好主意。我通常按照以下顺序尝试这些方法,直到其中一个有效为止:
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.
我正在做一个库,提供类的代码功能,Javascript,目前它支持构造函数,继承,方法重载参数的数量和参数的类型,混合,静态属性和单例。
请参阅使用该库的方法重载示例:
eutsiv.define('My.Class', {
constructor: function() {
this.y = 2;
},
x: 3,
sum: function() {
return this.x + this.y;
},
overloads: {
value: [
function() { return this.x + ', ' + this.y },
function(p1) { this.x = p1; },
function(p1, p2) { this.x = p1; this.y = p2; } // will set x and y
]
}
});
var test = new My.Class({ x: 5 }); // create the object
test.value(); // will return '5, 2'
test.sum(); // will return 7
test.value(13); // will set x to 13
test.value(); // will return '13, 2'
test.sum(); // will return 15
test.value(10, 20); // will set x to 10 and y to 20
test.value(); // will return '10, 20'
test.sum(); // will return 30
欢迎任何反馈,bug修复,文档和测试改进!
https://github.com/eutsiv/eutsiv.js
看看这个。它很酷。 http://ejohn.org/blog/javascript-method-overloading/ 技巧Javascript,让你做这样的调用:
var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name