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!!");}}
var users = new Users();users.find(); // Finds allusers.find("John"); // Finds users by nameusers.find("John", "Resig"); // Finds users by first and last name
TEST = {};
TEST.multiFn = function(){// function map for our overloadsvar 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 closurethis.multiFn = function(){fnMap[arguments.length].apply(this, arguments);return this;};
// call the function since this code will only run oncethis.multiFn.apply(this, arguments);
return this;};
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 objecttest.value(); // will return '5, 2'test.sum(); // will return 7test.value(13); // will set x to 13test.value(); // will return '13, 2'test.sum(); // will return 15test.value(10, 20); // will set x to 10 and y to 20test.value(); // will return '10, 20'test.sum(); // will return 30
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));
var foo;
// original 'foo' definitionfoo = function(a) {console.log("a: " + a);}
// define 'foo' to accept two argumentsfoo = (function() {// store a reference to the previous definition of 'foo'var old = foo;
// use inline function so that you can refer to it internallyreturn 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: 1foo(1,2);> a: 1> b: 2foo(1,2,3)> a: 1
// addMethod - By Stavros Ioannidisfunction addMethod(obj, name, fn) {obj[name] = obj[name] || function() {// get the cached method with arguments.length argumentsvar method = obj[name].cache[arguments.length];
// if method exists call itif ( !! method)return method.apply(this, arguments);else throw new Error("Wrong number of arguments");};
// initialize obj[name].cacheobj[name].cache = obj[name].cache || {};
// Check if a method with the same number of arguments existsif ( !! 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 argumentsobj[name].cache[fn.length] = function() {return fn.apply(this, arguments);};}
function Clear(control){var o = typeof control !== "undefined" ? control : document.body;var children = o.childNodes;while (o.childNodes.length > 0)o.removeChild(o.firstChild);}
/** 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"
function foo(...args){return window['foo_' + args.length+'_'+Array.from(args).map((arg)=>typeof arg).join('_')](...args);
}//------Assuming that `x` , `y` and `z` are String when calling `foo` .
/**-- for : foo(x)*/function foo_1_string(){}/**-- for : foo(x,y,z) ---*/function foo_3_string_string_string(){
}
#其他复杂样本:
function foo(...args){return window['foo_'+args.length+'_'+Array.from(args).map((arg)=>typeof arg).join('_')](...args);}
/** one argument & this argument is string */function foo_1_string(){
}//------------/** one argument & this argument is object */function foo_1_object(){
}//----------/** two arguments & those arguments are both string */function foo_2_string_string(){
}//--------/** Three arguments & those arguments are : id(number),name(string), callback(function) */function foo_3_number_string_function(){let args=arguments;new Person(args[0],args[1]).onReady(args[3]);}
//--- And so on ....
// if we have a function defined belowfunction fooYo(){// do something here}// on invoking fooYo with different number of arguments it should be capable to do different things
fooYo(); // does TASK1fooYo('sagar'); // does TASK2fooYo('sagar','munjal'); // does TAKS3
注意-JS不提供函数重载的内置能力。
替代
John E Resig(JS的创建者)指出了一种替代方案,它使用上述先决条件来实现实现函数重载的能力。
下面的代码通过使用if-else或switch语句使用了简单但天真的方法。
计算argument-length属性。
不同的值会导致调用不同的函数。
var ninja = {whatever: function() {switch (arguments.length) {case 0:/* do something */break;case 1:/* do something else */break;case 2:/* do yet something else */break;//and so on ...}}}
var ninja = {};debugger;
addMethod(ninja,'whatever',function(){ console.log("I am the one with ZERO arguments supplied") });addMethod(ninja,'whatever',function(a){ console.log("I am the one with ONE arguments supplied") });addMethod(ninja,'whatever',function(a,b){ console.log("I am the one with TWO arguments supplied") });
ninja.whatever();ninja.whatever(1,2);ninja.whatever(3);
window.overload = function () {"use strict"
var a_fnOverloads = [],_Object_prototype_toString = Object.prototype.toString;
function isFn(f) {return (_Object_prototype_toString.call(f) === '[object Function]');} //# isFn
function isObj(o) {return !!(o && o === Object(o));} //# isObj
function isArr(a) {return (_Object_prototype_toString.call(a) === '[object Array]');} //# isArr
function mkArr(a) {return Array.prototype.slice.call(a);} //# mkArr
function fnCall(fn, vContext, vArguments) {//# <ES5 Support for array-like objects//# See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Browser_compatibilityvArguments = (isArr(vArguments) ? vArguments : mkArr(vArguments));
if (isFn(fn)) {return fn.apply(vContext || this, vArguments);}} //# fnCall
//#function registerAlias(fnOverload, fn, sAlias) {//#if (sAlias && !fnOverload[sAlias]) {fnOverload[sAlias] = fn;}} //# registerAlias
//#function overload(vOptions) {var oData = (isFn(vOptions) ?{ default: vOptions } :(isObj(vOptions) ?vOptions :{default: function (/*arguments*/) {throw "Overload not found for arguments: [" + mkArr(arguments) + "]";}})),fnOverload = function (/*arguments*/) {var oEntry, i, j,a = arguments,oArgumentTests = oData[a.length] || [];
//# Traverse the oArgumentTests for the number of passed a(rguments), defaulting the oEntry at the beginning of each loopfor (i = 0; i < oArgumentTests.length; i++) {oEntry = oArgumentTests[i];
//# Traverse the passed a(rguments), if a .test for the current oArgumentTests fails, reset oEntry and fall from the a(rgument)s loopfor (j = 0; j < a.length; j++) {if (!oArgumentTests[i].tests[j](a[j])) {oEntry = undefined;break;}}
//# If all of the a(rgument)s passed the .tests we found our oEntry, so break from the oArgumentTests loopif (oEntry) {break;}}
//# If we found our oEntry above, .fn.call its .fnif (oEntry) {oEntry.calls++;return fnCall(oEntry.fn, this, a);}//# Else we were unable to find a matching oArgumentTests oEntry, so .fn.call our .defaultelse {return fnCall(oData.default, this, a);}} //# fnOverload;
//#fnOverload.add = function (fn, a_vArgumentTests, sAlias) {var i,bValid = isFn(fn),iLen = (isArr(a_vArgumentTests) ? a_vArgumentTests.length : 0);
//#if (bValid) {//# Traverse the a_vArgumentTests, processinge each to ensure they are functions (or references to )for (i = 0; i < iLen; i++) {if (!isFn(a_vArgumentTests[i])) {bValid = _false;}}}
//# If the a_vArgumentTests are bValid, set the info into oData under the a_vArgumentTests's iLenif (bValid) {oData[iLen] = oData[iLen] || [];oData[iLen].push({fn: fn,tests: a_vArgumentTests,calls: 0});
//#registerAlias(fnOverload, fn, sAlias);
return fnOverload;}//# Else one of the passed arguments was not bValid, so throw the errorelse {throw "poly.overload: All tests must be functions or strings referencing `is.*`.";}}; //# overload*.add
//#fnOverload.list = function (iArgumentCount) {return (arguments.length > 0 ? oData[iArgumentCount] || [] : oData);}; //# overload*.list
//#a_fnOverloads.push(fnOverload);registerAlias(fnOverload, oData.default, "default");
return fnOverload;} //# overload
//#overload.is = function (fnTarget) {return (a_fnOverloads.indexOf(fnTarget) > -1);} //# overload.is
return overload;}();
function foo(var1, var2, opts){// set default values for parametersconst defaultOpts = {a: [1,2,3],b: true,c: 0.3289,d: "str",}// merge default and passed-in parameters// defaultOpts must go first!const mergedOpts = {...defaultOpts, ...opts};
// you can now refer to parameters like b as mergedOpts.b,// or just assign mergedOpts.b to bconsole.log(mergedOpts.a);console.log(mergedOpts.b);console.log(mergedOpts.c);console.log(mergedOpts.d);}// the parameters you passed in override the default ones// all JS types are supported: primitives, objects, arrays, functions, etc.let var1, var2="random var";foo(var1, var2, {a: [1,2], d: "differentString"});
// parameter values inside foo://a: [1,2]//b: true//c: 0.3289//d: "differentString"
function addCSS(el, prop, val) {return {2: function() {// when two arguments are set// now prop is an ojectfor (var i in prop) {el.style[i] = prop[i];}},3: function() {// when three arguments are setel.style[prop] = val;}}[arguments.length]();}// usagevar el = document.getElementById("demo");addCSS(el, "color", "blue");addCSS(el, {"backgroundColor": "black","padding": "10px"});
function sayHi(a, b) {console.log('hi there ' + a);if (b) { console.log('and ' + b) } // if the parameter is present, execute the block}
sayHi('Frank', 'Willem');
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 cardif (typeof x == "object") {let pickedCard = Math.floor(Math.random() * x.length);return pickedCard;}// Otherwise just let them pick the cardelse 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);