在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
在Javascript中伪造函数重载的最好方法是什么?
我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:
一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?
当前回答
有两种方法可以更好地解决这个问题:
如果您希望保留很大的灵活性,则传递一个字典(关联数组) 将一个对象作为参数,并使用基于原型的继承来增加灵活性。
其他回答
Javascript中的函数重载:
函数重载是一种编程语言用不同的实现创建多个同名函数的能力。当重载函数被调用时,它将运行该函数的特定实现,以适应调用的上下文。这个上下文通常是接收参数的数量,它允许一个函数调用根据上下文表现不同。
Javascript没有内置的函数重载。然而,这种行为可以通过许多方式来模仿。这里有一个简单方便的例子:
函数sayHi(a, b) { Console.log ('hi there ' + a); 如果(b) {console.log('and ' + b)} //如果参数存在,则执行该块 } sayHi(“弗兰克”,“威廉”);
在你不知道你将得到多少参数的情况下,你可以使用rest操作符,即三点....它将把剩余的参数转换为一个数组。但是要注意浏览器的兼容性。这里有一个例子:
函数foo (a,…b) { console.log (b); } foo(1、2、3、4); foo(1、2);
下面是一种使用参数类型允许真正的方法重载的方法,如下所示:
Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);
Edit(2018):自2011年编写以来,直接方法调用的速度大大提高,而重载方法的速度却没有提高。
这不是我推荐的方法,但思考如何解决这类问题是一个值得思考的练习。
这里是不同方法的基准测试- https://jsperf.com/function-overloading。它显示函数重载(考虑到类型)可以在谷歌Chrome的V8 16.0(测试版)慢大约13倍。
除了传递一个对象(例如{x: 0, y: 0}),还可以在适当的时候采用C方法,相应地命名方法。例如,vector . addvector (vector), vector . addvector。AddIntegers(x, y, z,…)和Vector.AddArray(integerArray)。您可以查看C库,例如OpenGL,以获得命名灵感。
编辑:我已经添加了一个基准,用于传递一个对象,并使用arg和arg. hasownproperty ('param')中的'param'测试对象,函数重载比传递一个对象和检查属性快得多(至少在这个基准测试中)。
From a design perspective, function overloading is only valid or logical if the overloaded parameters correspond to the same action. So it stands to reason that there ought to be an underlying method that is only concerned with specific details, otherwise that may indicate inappropriate design choices. So one could also resolve the use of function overloading by converting data to a respective object. Of course one must consider the scope of the problem as there's no need in making elaborate designs if your intention is just to print a name, but for the design of frameworks and libraries such thought is justified.
我的例子来自一个矩形实现——因此提到了维和点。也许Rectangle可以向Dimension and Point原型添加一个GetRectangle()方法,然后对函数重载问题进行排序。那原语呢?好的,我们有参数length,这现在是一个有效的测试,因为对象有一个GetRectangle()方法。
function Dimension() {}
function Point() {}
var Util = {};
Util.Redirect = function (args, func) {
'use strict';
var REDIRECT_ARGUMENT_COUNT = 2;
if(arguments.length - REDIRECT_ARGUMENT_COUNT !== args.length) {
return null;
}
for(var i = REDIRECT_ARGUMENT_COUNT; i < arguments.length; ++i) {
var argsIndex = i-REDIRECT_ARGUMENT_COUNT;
var currentArgument = args[argsIndex];
var currentType = arguments[i];
if(typeof(currentType) === 'object') {
currentType = currentType.constructor;
}
if(typeof(currentType) === 'number') {
currentType = 'number';
}
if(typeof(currentType) === 'string' && currentType === '') {
currentType = 'string';
}
if(typeof(currentType) === 'function') {
if(!(currentArgument instanceof currentType)) {
return null;
}
} else {
if(typeof(currentArgument) !== currentType) {
return null;
}
}
}
return [func.apply(this, args)];
}
function FuncPoint(point) {}
function FuncDimension(dimension) {}
function FuncDimensionPoint(dimension, point) {}
function FuncXYWidthHeight(x, y, width, height) { }
function Func() {
Util.Redirect(arguments, FuncPoint, Point);
Util.Redirect(arguments, FuncDimension, Dimension);
Util.Redirect(arguments, FuncDimensionPoint, Dimension, Point);
Util.Redirect(arguments, FuncXYWidthHeight, 0, 0, 0, 0);
}
Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);
在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!!");
}
}
好运!
我经常这样做:
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测试
多年来,我一直在使用这个函数来美化我的重载:
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 );
} );
}
许多重载函数在优化性能时几乎不可读。你必须破译函数的头部。这可能比使用我提供的重载函数更快;但是,从人的角度来看,它在识别调用了哪个重载方面要慢一些。