在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
多年来,我一直在使用这个函数来美化我的重载:
function overload(){
const fs = arguments, fallback = fs[fs.length - 1];
return function(){
const f = fs[arguments.length] || (arguments.length >= fs.length ? fallback : null);
return f.apply(this, arguments);
}
}
型:
function curry1(f){
return curry2(f, f.length);
}
function curry2(f, minimum){
return function(...applied){
if (applied.length >= minimum) {
return f.apply(this, applied);
} else {
return curry2(function(...args){
return f.apply(this, applied.concat(args));
}, minimum - applied.length);
}
}
}
export const curry = overload(null, curry1, curry2);
看看jQuery的off方法:
function off( types, selector, fn ) {
var handleObj, type;
if ( types && types.preventDefault && types.handleObj ) {
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
handleObj.namespace ?
handleObj.origType + "." + handleObj.namespace :
handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
// ( types-object [, selector] )
for ( type in types ) {
this.off( type, selector, types[ type ] );
}
return this;
}
if ( selector === false || typeof selector === "function" ) {
// ( types [, fn] )
fn = selector;
selector = undefined;
}
if ( fn === false ) {
fn = returnFalse;
}
return this.each( function() {
jQuery.event.remove( this, types, fn, selector );
} );
}
许多重载函数在优化性能时几乎不可读。你必须破译函数的头部。这可能比使用我提供的重载函数更快;但是,从人的角度来看,它在识别调用了哪个重载方面要慢一些。
其他回答
所以我真的很喜欢这种做事的方式,这是我在javascript忍者的秘密中发现的
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将重载函数添加到任何对象。对我来说,这段代码中的主要困惑是fn的使用。Length ==参数。长度,这是因为fn。长度是预期参数的数量,而参数。长度是函数实际调用的参数的数量。匿名函数没有参数的原因是你可以在javascript中传入任意数量的参数,并且语言是宽容的。
我喜欢这个,因为你可以在任何地方使用它-只需创建这个函数,并在任何你想要的代码库中简单地使用这个方法。
它还避免了一个大得离谱的if/switch语句,如果您开始编写复杂的代码,它将变得难以阅读(接受的答案将导致这种结果)。
在缺点方面,我想代码一开始有点晦涩……但我不确定其他人?
多年来,我一直在使用这个函数来美化我的重载:
function overload(){
const fs = arguments, fallback = fs[fs.length - 1];
return function(){
const f = fs[arguments.length] || (arguments.length >= fs.length ? fallback : null);
return f.apply(this, arguments);
}
}
型:
function curry1(f){
return curry2(f, f.length);
}
function curry2(f, minimum){
return function(...applied){
if (applied.length >= minimum) {
return f.apply(this, applied);
} else {
return curry2(function(...args){
return f.apply(this, applied.concat(args));
}, minimum - applied.length);
}
}
}
export const curry = overload(null, curry1, curry2);
看看jQuery的off方法:
function off( types, selector, fn ) {
var handleObj, type;
if ( types && types.preventDefault && types.handleObj ) {
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
handleObj.namespace ?
handleObj.origType + "." + handleObj.namespace :
handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
// ( types-object [, selector] )
for ( type in types ) {
this.off( type, selector, types[ type ] );
}
return this;
}
if ( selector === false || typeof selector === "function" ) {
// ( types [, fn] )
fn = selector;
selector = undefined;
}
if ( fn === false ) {
fn = returnFalse;
}
return this.each( function() {
jQuery.event.remove( this, types, fn, selector );
} );
}
许多重载函数在优化性能时几乎不可读。你必须破译函数的头部。这可能比使用我提供的重载函数更快;但是,从人的角度来看,它在识别调用了哪个重载方面要慢一些。
我喜欢@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);
}
对于函数重载,可以这样做。
function addCSS(el, prop, val) {
return {
2: function() {
// when two arguments are set
// now prop is an oject
for (var i in prop) {
el.style[i] = prop[i];
}
},
3: function() {
// when three arguments are set
el.style[prop] = val;
}
}[arguments.length]();
}
// usage
var el = document.getElementById("demo");
addCSS(el, "color", "blue");
addCSS(el, {
"backgroundColor": "black",
"padding": "10px"
});
源
我不确定最佳实践,但我是这样做的:
/*
* 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"