如何在JavaScript中比较两个函数? 我不是在谈论内部引用。请说。
var a = function(){return 1;};
var b = function(){return 1;};
可以比较a
和b
吗?
如何在JavaScript中比较两个函数? 我不是在谈论内部引用。请说。
var a = function(){return 1;};
var b = function(){return 1;};
可以比较a
和b
吗?
var a = b = function( c ){ return c; };
//here, you can use a === b because they're pointing to the same memory and they're the same type
var a = function( c ){ return c; },
b = function( c ){ return c; };
//here you can use that byte-saver Andy E used (which is implicitly converting the function to it's body's text as a String),
''+a == ''+b.
//this is the gist of what is happening behind the scences:
a.toString( ) == b.toString( )
闭包意味着在说“比较”时需要非常小心。例如:
function closure( v ) { return function(){return v} };
a = closure('a'); b = closure('b');
[a(), b()]; // ["a", "b"]
// Now, are a and b the same function?
// In one sense they're the same:
a.toString() === b.toString(); // true, the same code
// In another sense they're different:
a() === b(); // false, different answers
// In a third sense even that's not enough:
a2 = closure('a');
a() === a2(); // true
a === a2; // false, not the same object
能够访问函数之外的能力意味着通常情况下比较函数是不可能的。
然而,在实际操作中,您可以使用像Esprima或Acorn这样的Javascript解析库来取得很长的进展。这些库允许您构建一个“抽象语法树”(AST),它是您程序的JSON描述。例如,您的return 1
函数的AST看起来像这样:
ast = acorn.parse('return 1', {allowReturnOutsideFunction:true});
console.log( JSON.stringify(ast), null, 2)
{
"body": [
{
"argument": {
"value": 1, // <- the 1 in 'return 1'
"raw": "1",
"type": "Literal"
},
"type": "ReturnStatement" // <- the 'return' in 'return 1'
}
],
"type": "Program"
}
// Elided for clarity - you don't care about source positions
您可以比较两个可能包含函数引用的变量,以查看它们是否引用相同的函数,但您无法真正比较两个不同的函数以查看它们是否执行相同的操作。
例如,您可以这样做:
function foo() {
return 1;
}
var a = foo;
var b = foo;
a == b; // true
但是,您不能可靠地做到这一点:
function foo1() {
return 1;
}
function foo2() {
return 1;
}
var a = foo1;
var b = foo2;
a == b; // false
.toString()
运算符,但这只是将您的函数的字面字符串转换与另一个函数进行比较,即使相差很少,也不会起作用。我想不出任何情况下我会推荐这种可靠的比较机制。如果您真的考虑以这种方式做,我会问为什么?您真正想要实现什么并尝试找到更强大的解决问题的方法。函数的toString()方法可以返回该函数的完整声明。您可以修改jfriend00的代码进行测试。
这意味着您可以测试您的函数是否完全相同,包括您在其中添加的空格和换行符。
但首先您需要消除它们名称上的差异。
function foo1() {
return 1;
}
function foo2() {
return 1;
}
//Get a string of the function declaration exactly as it was written.
var a = foo1.toString();
var b = foo2.toString();
//Cut out everything before the curly brace.
a = a.substring(a.indexOf("{"));
b = b.substring(b.indexOf("{"));
//a and b are now this string:
//"{
// return 1;
//}"
alert(a == b); //true.
正如其他人所说,这种方法不可靠,因为只要有一个空格不同就会使比较结果为false。
但是如果你把它用作一种保护措施呢?(“自从我创建函数以来,有人修改了它吗?”)那么你可能真的希望进行严格的比较。
使用模板字面量的ES6+干净解决方案:
const fn1 = () => {}
const fn2 = () => {}
console.log(`${fn1}` === `${fn2}`) // true
基本上意味着:
console.log(fn1.toString() === fn2.toString()) // true
将函数转换为字符串,然后替换换行符和空格以进行比较:
let a = function () {
return 1
};
let b = function () {
return 1
};
a = a.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');
b = b.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');
console.log(a); // 'function () { return 1}'
console.log(b); // 'function () { return 1}'
console.log(a === b); // true
b = function () {
return 2
};
b = b.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');
console.log(b); // 'function () { return 2}'
console.log(a === b); // false
b = () => 3;
b = b.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');
console.log(b); // '() => 3'
console.log(a === b); // false
附言:如果您正在使用ES6,请尝试使用let
而不是var
。
a
或b
)。我还认为有一些库可以“反射”JavaScript[在脚本块中]。 - user166390