Как сравнить 2 функции в JavaScript - PullRequest
46 голосов
/ 22 марта 2012

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

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

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

Ответы [ 5 ]

51 голосов
/ 22 марта 2012
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( )  
15 голосов
/ 18 августа 2015

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

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

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

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

8 голосов
/ 22 марта 2012

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

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

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() для функций, но это сравнивает буквальное преобразование строки вашей функции друг с другом, которая, даже если она отключается на крошечный бит, который не имеет значения для того, что она на самом деле производит, не будет работать. Я не могу представить себе ситуацию, в которой я бы рекомендовал это как надежный механизм сравнения. Если бы вы серьезно задумывались о том, чтобы сделать это таким образом, я бы спросил, почему? Чего вы действительно пытаетесь достичь и пытаетесь найти более надежный способ решения проблемы.

2 голосов
/ 15 ноября 2017

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.

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

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

0 голосов
/ 25 августа 2016

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

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

p / s: если вы используете ES6, попробуйте использовать let вместо var.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...