我正在尝试找到一种确定函数对象参数的方法,以便我可以确定它们各自的类型。
Params.prototype.getParams = function (fn) {
var a = fn.length;
console.log("Args: " + a);
for (var i = 0; i < a; i++) {
// This is where I want to print the type
console.log("Arg[" + i + "] type is: " + typeof(fn.arguments[i]));
}
}
然后,如果我定义了一些函数(可以是任何JS函数),例如:
function callback1("one") {}
function callback2("one", 2) {}
function callback3(1, "two", []) {}
如果我以后再调用每个:
var params = new Params();
params.getParams(callback1);
params.getParams(callback2);
params.getParams(callback3);
我想弄清楚每个函数实例的每个param类型。我已谷歌了,在搜索它,但找不到任何有用的东西。如果它知道'长度',我不明白为什么它也不知道参数?
更新 - 2013.02.19 17:41
是的,我知道上面的代码中存在潜在的错误,我为了简化阅读而剥离了它。
这是我想要完成的事情:
我正在阅读这篇(有趣的)文章:JavaScript Function Overloading
来自Java并且是一个纯粹主义者,我想开始尝试方法重载(该死的我无法相信原始的JS是多么)。
我希望通过将“函数计数”方法替换为使用参数类型的方法来“增强”本文中的示例,而不是“解析”应该调用哪个重载函数。看起来这只是通过在我的例子中实际知道'fn'的参数类型来实现的。
答案 0 :(得分:4)
function fun(a,b,c) {... }
在JavaScript中,任何变量或函数参数都可以包含任何类型的对象或基元。
唯一的方法是在运行时使用arguments
function callback3(a,b,c) {
if (typeof a != 'string') {
throw new Error('callback3 expects a string for its first argument');
}
}
因为看起来你想要键入检查,你可以用
之类的东西来抽象它function checkParams(args, types) {
if (args.length != types.length) {
throw new Error('Invalid number of arguments passed');
}
for (var i=0; i < args.length; i ++) {
if (typeof args[i] != types[i]) {
throw new Error('Argument number '+ i +' has wrong type');
}
}
}
function callback3(a,b,c) {
checkParams(arguments, ['string', 'number', 'object') );
// rest of the code
}
答案 1 :(得分:1)
函数参数没有类型,如果你想要一些类似重载的东西,你需要自己实现它。
使用它的最简单方法是重载getter,像jQuery这样的setter方法用于val()
和许多其他函数。如果你没有传递任何东西,它会检索该值,如果你传递了某些东西,它将设置一个值。我写的东西与John Resig建议的略有不同。这样,你将有两个例子可以看。
重要的是你无法检索参数类型,只能检索函数定义中声明的参数数量。
function overload(/*fun1, fun2, fun3... */) {
var overloadedFuns = arguments;
return function() {
var argCount = arguments.length;
for (var i=0; i < overloadedFuns.length; i++) {
if (overloadedFuns[i].length === argCount) {
return overloadedFuns[i].apply(this, arguments);
break;
}
}
}
}
var obj = {
_val = 0;
val: overload(
// This will get called when called with no arguments
function() {
return this._val;
},
// This will get called when called with one arguments
function(val){
this._val = val;
}
)
}
console.log( obj.val() ); // Outputs 0
obj.val(5); // Sets it to 5
console.log( obj.val() ); // Outputs 5
可以引入类似的概念来添加类型。但由于您无法从函数定义中推断出类型,因此您需要自己添加该信息
示例: http://jsfiddle.net/UPuwE/1/
/**
* @param {object[]} fnDefs, Each object should contain a paramList and a fn
* {paramMap: ["string"], fn: function() {myString}}
*
*/
function overload(fnDefs) {
function matches(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
for (var i=0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return false;
}
}
return true;
}
return function() {
var types = [];
for (var i =0; i < arguments.length; i++) {
types.push(typeof arguments[i]);
}
for (var i=0; i < fnDefs.length; i++) {
if (matches(types, fnDefs[i].paramMap)) {
return fnDefs[i].fn.apply(this, arguments);
}
}
}
}
var obj = {
_val: 0,
val: overload([
{
paramMap: ['string'],
fn: function(str) {
this._val = str;
}
},
{
paramMap: ['object'],
// If an object is passed in, grab the string from its
// str property or by calling the toString() method;
fn: function(obj) {
this._val = obj.str || obj.toString();
}
},
{
paramMap: [],
// Getter
fn: function(obj) {
return this._val;
}
}
])
};
obj.val('34');
console.log( obj.val() );
obj.val({str: '35'});
console.log( obj.val() );
obj.val( {toString: function(){return '36';} } );
console.log( obj.val() );
我希望这个例子向您展示运行时有很多开销,这就是大多数库不使用它的原因
答案 2 :(得分:0)
您在寻找arguments
变量吗?
function sayHi(name) {console.log(arguments)}
sayHi('hackNightly')
>>> ['hackNightly']
好像你有参数,你可以循环遍历它们并使用typeOf()或类似的东西进行类型检查。
答案 3 :(得分:0)
函数对象不再存储其参数,可以使用var arguments
直接在函数调用中使用它们。
http://www.sitepoint.com/arguments-a-javascript-oddity/
//try this instead
console.log("Arg[" + i + "] type is: " + typeof(arguments[i]));
答案 4 :(得分:0)
我有一个小时的闲暇时间,所以我想我会尝试实施我从'Juan Mendes'和'系统'中收到的各种建议。
以下只是一个工作示例(未优化,未进行基准测试,未清理),因此请考虑它正在进行中。在我做任何其他事情之前,我会想要运行一些基准来看看它最终会提供什么样的“膨胀”。
如果有人对此有任何不妥之处,请提出建设性的批评!
function Overload() {
// Empty for now!
}
Overload.prototype.link = function (object, method) {
console.log("Creating dispatch method '" + method + "()'");
object.prototype[method] = function () {
var target = method + "_";
console.log("Invoked dispatch method '" + method + "()'...");
for (var i=0; i < arguments.length; i++) {
target += (typeof arguments[i]).substring(0, 1);
}
console.log("Resolved target as '" + target + "'");
if (typeof object.prototype._overloaded[target] !== "undefined") {
console.log("Dispatching to overloaded method: '" + target + "'");
return object.prototype._overloaded[target].apply(object, arguments);
} else {
console.log("Method not found: '" + method + "('" + target + "')'");
//throw "Exception ...";
}
}
}
以下函数将用于重载对象上的所有其他函数:
Overload.prototype.overload = function (object, method, fn, params) {
var target = method + "_" + params;
console.log("Overloading method '" + method + "()' to '" + method + "('" + params + "')'");
if (typeof object === "undefined") {
console.log("Object doesn't exist!");
}
if (typeof object.prototype[method] === "undefined") {
this.link(object, method);
}
if (typeof object.prototype._overloaded === "undefined") {
console.log("Creating '[obj].prototype._overloaded' property");
object.prototype._overloaded = {};
}
if (typeof object.prototype._overloaded[target] === "undefined") {
//console.log("Assigning overload function as target '" + method + "('" + params + "')'");
object.prototype._overloaded[target] = fn;
} else {
console.log("Definition for '" + method + "('" + params + "')' already eixsts!");
}
return fn;
}
现在定义一些基本上“模拟”重载函数的示例函数:
function fn1(one) {
console.log("Invoked function 1: " + one);
}
function fn2(one, two) {
console.log("Invoked function 2: " + one + ", " + two);
}
function fn3(one, two, three) {
console.log("Invoked function 3: " + one + ", " + two + ", " + three);
}
function fn4(one, two, three) {
console.log("Invoked function 4: " + one + ", " + two);
}
function fn5(one, two, three) {
console.log("Invoked function 5: " + one + ", " + two);
}
使用它来运行我们的测试:
function testMethodOverloading() {
console.log("Testing method overloading!");
var ov = new Overload();
function OBJ() {}
console.log("--");
ov.overload(OBJ, "name", fn1, 's');
ov.overload(OBJ, "name", fn2, 'sn');
ov.overload(OBJ, "name", fn3, 'sns');
ov.overload(OBJ, "name", fn4, 'ss');
ov.overload(OBJ, "name", fn5, 'nn');
console.log("--");
var obj = new OBJ();
obj.name("one");
obj.name("two", 1);
obj.name("three", 2, "four");
obj.name("five", "six");
obj.name(3, 4);
}
这是我从上面的测试中获得的输出:
Overloading method 'name()' to 'name('s')'
Creating dispatch method 'name()'
Creating '[obj].prototype._overloaded' property
Overloading method 'name()' to 'name('sn')'
Overloading method 'name()' to 'name('sns')'
Overloading method 'name()' to 'name('ss')'
Overloading method 'name()' to 'name('nn')'
--
Invoked dispatch method 'name()'...
Resolved target as 'name_s'
Dispatching to overloaded method: 'name_s'
Invoked function 1: one
Invoked dispatch method 'name()'...
Resolved target as 'name_sn'
Dispatching to overloaded method: 'name_sn'
Invoked function 2: two, 1
Invoked dispatch method 'name()'...
Resolved target as 'name_sns'
Dispatching to overloaded method: 'name_sns'
Invoked function 3: three, 2, four
Invoked dispatch method 'name()'...
Resolved target as 'name_ss'
Dispatching to overloaded method: 'name_ss'
Invoked function 4: five, six
Invoked dispatch method 'name()'...
Resolved target as 'name_nn'
Dispatching to overloaded method: 'name_nn'
Invoked function 5: 3, 4
所以它绝对按照我的预期/想要的方式运行!但它会得到什么样的基准。我将在接下来做这个,看看我是否在所引用文章的基准测试范围内的任何地方(在剥离所有日志记录之后)。一旦我有了一个大致的想法,我会发布结果。