在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
介绍
到目前为止,阅读这么多答案会让任何人感到头疼。任何试图了解这个概念的人都需要知道以下先决条件。
函数重载定义,函数长度属性,函数参数属性
最简单形式的函数重载意味着函数根据传递给它的参数数量执行不同的任务。值得注意的是TASK1, TASK2和TASK3在下面突出显示,它们是根据传递给同一个函数fooYo的参数数量来执行的。
// if we have a function defined below
function fooYo(){
// do something here
}
// on invoking fooYo with different number of arguments it should be capable to do different things
fooYo(); // does TASK1
fooYo('sagar'); // does TASK2
fooYo('sagar','munjal'); // does TAKS3
请注意 JS不提供内置的函数重载功能。
替代
John E Resig (JS的创建者)指出了一种替代方法,它使用上述先决条件来实现函数重载的能力。
下面的代码通过使用if-else或switch语句使用了一种简单但简单的方法。
计算参数长度属性。 不同的值导致调用不同的函数。
Var ninja = { function() { 切换(arguments.length) { 例0: /*做某事*/ 打破; 案例1: /* do something else */ 打破; 案例2: /*做其他事情*/ 打破; //等等… } } }
另一种技术更加简洁和动态。这项技术的亮点是addMethod泛型函数。
我们定义了一个addMethod函数,它用于向一个对象添加不同的函数,这些函数具有相同的名称但不同的功能。 下面的addMethod函数接受三个参数:对象名称object,函数名称name和我们想要调用的函数fn。 在addMethod定义中,var old存储了对前一个函数的引用,该函数通过闭包(一个保护气泡)的帮助存储。
函数addMethod(对象,名称,fn) { Var old =对象[name]; 对象[name] = function(){ 如果(fn)。Length == arguments.length) 返回fn。应用(这个参数) Else if (typeof old == 'function') 返回旧。应用(这个参数); }; };
使用调试器来理解代码流。 下面的addMethod添加了三个函数,当使用ninja.whatever(x)调用时,参数x的数量可以是任何东西,即空白或一个或多个调用不同的函数定义,同时使用addMethod函数。
Var ninja = {}; 调试器; addMethod(ninja,'whatever',function(){console.log("我是那个提供了零参数的人")}); addMethod(ninja,'whatever',function(a){console.log("我是提供了一个参数的人")}); addMethod(ninja,'whatever',function(a,b){console.log("我是一个提供了两个参数的人")}); ninja.whatever (); ninja.whatever(1、2); ninja.whatever (3);
其他回答
第一个选项确实值得注意,因为这是我在相当复杂的代码设置中遇到的问题。所以,我的答案是
一开始就用不同的名字
有一个小但重要的提示,名称应该看起来不同的计算机,但不是你。命名重载函数,如func, func1, func2。
这是一个老问题,但我认为需要另一个条目(尽管我怀疑是否有人会读它)。立即调用函数表达式(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。此模式可以重复任意次数,以赋予一个变量若干不同的函数定义。
Typescript手册提到了重载。虽然前面已经提到过检查类型和根据结果执行不同的逻辑,但这种定义多个命名函数来使用类型系统的方法可能会让读者感兴趣。下面是TypeScript如何实现创建一个接受多种类型参数的函数,这些参数将指导函数逻辑根据传入的参数和类型做不同的事情:
答案是为同一个函数提供多个函数类型作为重载列表。这个列表是编译器用来解析函数调用的。让我们创建一个重载列表,用来描述pickCard接收和返回的内容。
let suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x: any): any {
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
let myDeck = [
{ suit: "diamonds", card: 2 },
{ suit: "spades", card: 10 },
{ suit: "hearts", card: 4 },
];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);
有了这个更改,重载现在为我们提供了对pickCard函数的类型检查调用。
为了让编译器选择正确的类型检查,它遵循与底层JavaScript类似的过程。它查看重载列表,然后继续执行第一个重载,尝试使用提供的参数调用函数。如果找到匹配项,则选择此重载作为正确的重载。出于这个原因,通常按照最特定到最不特定的顺序对重载进行排序。
注意,函数pickCard(x):任何块都不是重载列表的一部分,因此它只有两个重载:一个接受对象,另一个接受数字。用任何其他参数类型调用pickCard都会导致错误。
在javascript中没有办法实现函数重载。 因此,我推荐使用下面的by typeof()方法而不是 多重功能伪造过载。
function multiTypeFunc(param)
{
if(typeof param == 'string') {
alert("I got a string type parameter!!");
}else if(typeof param == 'number') {
alert("I got a number type parameter!!");
}else if(typeof param == 'boolean') {
alert("I got a boolean type parameter!!");
}else if(typeof param == 'object') {
alert("I got a object type parameter!!");
}else{
alert("error : the parameter is undefined or null!!");
}
}
好运!
介绍
到目前为止,阅读这么多答案会让任何人感到头疼。任何试图了解这个概念的人都需要知道以下先决条件。
函数重载定义,函数长度属性,函数参数属性
最简单形式的函数重载意味着函数根据传递给它的参数数量执行不同的任务。值得注意的是TASK1, TASK2和TASK3在下面突出显示,它们是根据传递给同一个函数fooYo的参数数量来执行的。
// if we have a function defined below
function fooYo(){
// do something here
}
// on invoking fooYo with different number of arguments it should be capable to do different things
fooYo(); // does TASK1
fooYo('sagar'); // does TASK2
fooYo('sagar','munjal'); // does TAKS3
请注意 JS不提供内置的函数重载功能。
替代
John E Resig (JS的创建者)指出了一种替代方法,它使用上述先决条件来实现函数重载的能力。
下面的代码通过使用if-else或switch语句使用了一种简单但简单的方法。
计算参数长度属性。 不同的值导致调用不同的函数。
Var ninja = { function() { 切换(arguments.length) { 例0: /*做某事*/ 打破; 案例1: /* do something else */ 打破; 案例2: /*做其他事情*/ 打破; //等等… } } }
另一种技术更加简洁和动态。这项技术的亮点是addMethod泛型函数。
我们定义了一个addMethod函数,它用于向一个对象添加不同的函数,这些函数具有相同的名称但不同的功能。 下面的addMethod函数接受三个参数:对象名称object,函数名称name和我们想要调用的函数fn。 在addMethod定义中,var old存储了对前一个函数的引用,该函数通过闭包(一个保护气泡)的帮助存储。
函数addMethod(对象,名称,fn) { Var old =对象[name]; 对象[name] = function(){ 如果(fn)。Length == arguments.length) 返回fn。应用(这个参数) Else if (typeof old == 'function') 返回旧。应用(这个参数); }; };
使用调试器来理解代码流。 下面的addMethod添加了三个函数,当使用ninja.whatever(x)调用时,参数x的数量可以是任何东西,即空白或一个或多个调用不同的函数定义,同时使用addMethod函数。
Var ninja = {}; 调试器; addMethod(ninja,'whatever',function(){console.log("我是那个提供了零参数的人")}); addMethod(ninja,'whatever',function(a){console.log("我是提供了一个参数的人")}); addMethod(ninja,'whatever',function(a,b){console.log("我是一个提供了两个参数的人")}); ninja.whatever (); ninja.whatever(1、2); ninja.whatever (3);