2012-03-22 3 views
31

Как сравнить 2 функции в javascript? Я не говорю о внутренней ссылке. СкажемКак сравнить 2 функции в javascript

var a = function(){return 1;}; 
var b = function(){return 1;}; 

Можно ли сравнить a и b?

+0

То, что JavaScript даже не разобрал, делает синтаксическую ошибку ... но, что вы подразумеваете под «сравнением»? Различные браузеры поддерживают «toString» по функциональным объектам по-разному, поэтому могут работать в вашем случае. (Но не в этом, потому что он не будет анализировать, поэтому ничего не назначено 'a' или' b'). Я также думаю, что есть некоторые библиотеки, чтобы «задуматься» о JavaScript [в блоках скриптов]. –

+0

, поскольку все объекты в JS - вы, вероятно, могли бы попытаться найти сравнение с аналогичным объектом (http://stackoverflow.com/questions/1068834/object-comparison-in-javascript) – shershen

ответ

37
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() 
+2

Обратите внимание, что это работает с анонимными функциями (которые , справедливо, то, что спросил ОП). Если у вас есть var a = function a() {.... и var b = function b() {... (что многие люди делают, потому что тогда вы получаете более значимые сообщения в своем стеке), тогда нет способа – gotofritz

8

Вы можете сравнить две переменные, которые могут содержать ссылки на функции, чтобы увидеть, если они относятся к той же самой функции, но вы не можете сравнить две отдельные функции, чтобы увидеть, если они делают то же самое.

Например, вы можете сделать это:

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 

Вы можете увидеть это второй здесь: http://jsfiddle.net/jfriend00/SdKsu/

Там есть некоторые обстоятельства, когда вы можете использовать оператор .toString() для функций, но это сравнение линейного преобразования строки вашей функции друг к другу, которое, i f даже от маленького бита, который несущественен для того, что он на самом деле производит, не будет работать. Я не могу думать ни о какой ситуации, где я бы рекомендовал это как надежный механизм сравнения. Если бы вы серьезно подумывали об этом, я бы спросил, почему? Что вы действительно пытаетесь выполнить и пытаетесь найти более надежный способ решения проблемы.

12

Закрытие означает, что вам нужно быть очень осторожным, что вы имеете в виду, когда говорите «сравнить». Например:

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 
// In another sense they're different: 
a() === b(); // false 

Способность достигать вне функции означает, что в общем смысле сравнение функций невозможно.

Однако в практическом смысле вы можете пройти очень долгий путь с помощью Javascript, анализирующих библиотеки, такие как Esprima или Acorn. Это позволит вам создать «Абстрактное синтаксическое дерево» (AST), которое представляет собой описание вашей программы JSON. Например, аст ваши return 1 функции выглядит следующим образом

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 

АСТ содержит всю информацию, необходимую для сравнения - это функция Javascript в виде данных. Вы можете нормализовать имена переменных, проверить закрытие, игнорировать даты и т. Д. В зависимости от ваших потребностей.

Существует множество инструментов и библиотек, которые помогают упростить процесс, но даже при том, что это, вероятно, будет большой работой и, вероятно, не практичным, но в основном это возможно.

0

Преобразовать функции в строку, а затем заменить разрыв строки и пространство перед сравнением:

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 ,

+0

это не работает, если объявить функцию типа «function a() {return 1;}»? –

+0

@TarekSalahuddinMahmud Вы можете попробовать еще раз. Я просто проверяю еще раз. Работает. –

0

Функция 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. 

Как говорили другие, это ненадежно, потому что одно пробел различия делает сравнение ложным.

Но что, если вы используете его в качестве защитной меры? («Кто-то изменил мою функцию с тех пор, как я ее создал?»). Тогда вы можете захотеть такого строгого сравнения.

Смежные вопросы