Как проверить, соответствуют ли два массива JavaScript?

var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);

alert(a == b + "|" + b == c);

демо

Как проверить этот массив на равенство и получить метод, который возвращает true, если они равны?

Предлагает ли jQuery какой-либо метод для этого?

Ответ 1

Это то, что вы должны сделать. Пожалуйста, не используйте stringify ни < >.

function arraysEqual(a, b) {
  if (a === b) return true;
  if (a == null || b == null) return false;
  if (a.length != b.length) return false;

  // If you don't care about the order of the elements inside
  // the array, you should sort both arrays here.
  // Please note that calling sort on an array will modify that array.
  // you might want to clone your array first.

  for (var i = 0; i < a.length; ++i) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

Ответ 2

Опция 1

Самый простой вариант, работает почти во всех случаях, за исключением того, что null ! == undefined но они оба преобразуются в null представление JSON и считаются равными:

function arraysEqual(a1,a2) {
    /* WARNING: arrays must not contain {objects} or behavior may be undefined */
    return JSON.stringify(a1)==JSON.stringify(a2);
}

(Это может не сработать, если ваш массив содержит объекты. Будет ли это работать с объектами, зависит от того, сортирует ли реализация JSON ключи. Например, JSON для {1:2,3:4} может быть равен или не равен {3:4,1:2}, это зависит от реализации, и спецификация не дает никаких гарантий. [Обновление 2017 года: На самом деле спецификация ES6 теперь гарантирует, что ключи объектов будут повторяться в порядке: 1) целочисленных свойств, 2) свойств в в порядке их определения 3) свойства символа в порядке их определения. Таким образом, ЕСЛИ за этим следует реализация JSON.stringify, равные объекты (в смысле ===, но НЕ ОБЯЗАТЕЛЬНО в смысле ==) будут преобразованы в равные значения. Необходимы дополнительные исследования. Так что, я думаю, вы могли бы создать злой клон объекта со свойствами в обратном порядке, но я не могу представить, чтобы это когда-либо происходило случайно...] По крайней мере в Chrome функция JSON.stringify имеет тенденцию возвращать ключи в порядке, в котором они были определены (по крайней мере, что я заметил), но это поведение очень подвержено изменениям в любой момент и не следует полагаться. Если вы решите не использовать объекты в своих списках, это должно работать нормально. Если у вас в списке есть объекты, которые имеют уникальный идентификатор, вы можете сделать a1.map(function(x)}{return {id:x.uniqueId}}). Если у вас есть произвольные объекты в вашем списке, вы можете прочитать вариант 2).

Это работает и для вложенных массивов.

Это, однако, немного неэффективно из-за накладных расходов, связанных с созданием этих строк и сборкой мусора.


Вариант 2

Более "правильная" опция, которую вы можете переопределить, чтобы иметь дело с особыми случаями (такими как обычные объекты и нулевые/неопределенные и пользовательские объекты, если вы того пожелаете):

// generally useful functions
function type(x) { // does not work in general, but works on JSONable objects we care about... modify as you see fit
    // e.g.  type(/asdf/g) --> "[object RegExp]"
    return Object.prototype.toString.call(x);
}
function zip(arrays) {
    // e.g. zip([[1,2,3],[4,5,6]]) --> [[1,4],[2,5],[3,6]]
    return arrays[0].map(function(_,i){
        return arrays.map(function(array){return array[i]})
    });
}

// helper functions
function allCompareEqual(array) {
    // e.g.  allCompareEqual([2,2,2,2]) --> true
    // does not work with nested arrays or objects
    return array.every(function(x){return x==array[0]});
}

function isArray(x){ return type(x)==type([]) }
function getLength(x){ return x.length }
function allTrue(array){ return array.reduce(function(a,b){return a&&b},true) }
    // e.g. allTrue([true,true,true,true]) --> true
    // or just array.every(function(x){return x});

function allDeepEqual(things) {
    // works with nested arrays
    if( things.every(isArray) )
        return allCompareEqual(things.map(getLength))     // all arrays of same length
               && allTrue(zip(things).map(allDeepEqual)); // elements recursively equal

    //else if( this.every(isObject) )
    //  return {all have exactly same keys, and for 
    //          each key k, allDeepEqual([o1[k],o2[k],...])}
    //  e.g. ... && allTrue(objectZip(objects).map(allDeepEqual)) 

    //else if( ... )
    //  extend some more

    else
        return allCompareEqual(things);
}

Демо-версия:

allDeepEqual([ [], [], [] ])
true
allDeepEqual([ [1], [1], [1] ])
true
allDeepEqual([ [1,2], [1,2] ])
true
allDeepEqual([ [[1,2],[3]], [[1,2],[3]] ])
true

allDeepEqual([ [1,2,3], [1,2,3,4] ])
false
allDeepEqual([ [[1,2],[3]], [[1,2],[],3] ])
false
allDeepEqual([ [[1,2],[3]], [[1],[2,3]] ])
false
allDeepEqual([ [[1,2],3], [1,[2,3]] ])
false

Чтобы использовать это как обычную функцию, выполните:

function allDeepEqual2() {
    return allDeepEqual([].slice.call(arguments));
}

Демо-версия:

allDeepEqual2([[1,2],3], [[1,2],3])
true

Варианты 3

редактировать: это 2016 год, и мой предыдущий слишком сложный ответ меня беспокоил. Эта рекурсивная, императивная реализация "рекурсивного программирования 101" делает код действительно простым и, более того, дает сбой в самом раннем случае (что дает нам эффективность). Он также не генерирует лишние эфемерные структуры данных (не то, чтобы что-то не так с функциональным программированием в целом, а просто с чистотой здесь).

Если бы мы хотели применить это к непустым массивам массивов, мы могли бы сделать seriesOfArrays.reduce(arraysEqual).

Это его собственная функция, в отличие от использования Object.defineProperties для присоединения к Array.prototype, так как это приведет к ошибке с ошибкой ключа, если мы передадим неопределенное значение (однако, если вы захотите это сделать, это будет хорошим решением),

Это только отвечает на оригинальный вопрос ОП.

function arraysEqual(a,b) {
    /*
        Array-aware equality checker:
        Returns whether arguments a and b are == to each other;
        however if they are equal-lengthed arrays, returns whether their 
        elements are pairwise == to each other recursively under this
        definition.
    */
    if (a instanceof Array && b instanceof Array) {
        if (a.length!=b.length)  // assert same length
            return false;
        for(var i=0; i<a.length; i++)  // assert each element equal
            if (!arraysEqual(a[i],b[i]))
                return false;
        return true;
    } else {
        return a==b;  // if not both arrays, should be the same
    }
}

Примеры:

arraysEqual([[1,2],3], [[1,2],3])
true
arraysEqual([1,2,3], [1,2,3,4])
false
arraysEqual([[1,2],[3]], [[1,2],[],3])
false
arraysEqual([[1,2],[3]], [[1],[2,3]])
false
arraysEqual([[1,2],3], undefined)
false
arraysEqual(undefined, undefined)
true
arraysEqual(1, 2)
false
arraysEqual(null, null)
true
arraysEqual(1, 1)
true
arraysEqual([], 1)
false
arraysEqual([], undefined)
false
arraysEqual([], [])
true

Если вы хотите применить это к JSON-подобным структурам данных с помощью js Objects, вы можете сделать это. К счастью, мы гарантируем, что все ключи объектов являются уникальными, поэтому перебираем объекты OwnProperties и сортируем их по ключу, затем утверждаем, что оба отсортированных ключа-массива равны, а массив значений равны, и просто повторяем. Мы можем расширить это, чтобы включить Карты (где ключи также уникальны). (Однако если мы расширим это до множеств, мы столкнемся с проблемой изоморфизма деревьев http://logic.pdmi.ras.ru/~smal/files/smal_jass08_slides.pdf - к счастью, это не так сложно, как изоморфизм общих графов; для его решения используется алгоритм O (#vertices), но это может быть очень сложно сделать эффективно. Патологический случай - если у вас есть набор, составленный из множества, казалось бы, неразличимых объектов, но при дальнейшей проверке некоторых из этих объектов может отличаться, если углубиться в них. Вы также можете обойти это, используя хеширование, чтобы отклонить почти все случаи.)


Вариант 4: (продолжение редактирования 2016 года)

Это должно работать с большинством объектов:

function deepEquals(a,b) {
    if (a instanceof Array && b instanceof Array)
        return arraysEqual(a,b);
    if (Object.getPrototypeOf(a)===Object.prototype && Object.getPrototypeOf(b)===Object.prototype)
        return objectsEqual(a,b);
    if (a instanceof Map && b instanceof Map)
        return mapsEqual(a,b);        
    if (a instanceof Set && b instanceof Set)
        throw "Error: set equality by hashing not implemented."
    if ((a instanceof ArrayBuffer || ArrayBuffer.isView(a)) && (b instanceof ArrayBuffer || ArrayBuffer.isView(b)))
        return typedArraysEqual(a,b);
    return a==b;  // see note[1] -- IMPORTANT
}

function arraysEqual(a,b) {
    if (a.length!=b.length)
        return false;
    for(var i=0; i<a.length; i++)
        if (!deepEquals(a[i],b[i]))
            return false;
    return true;
}
function objectsEqual(a,b) {
    var aKeys = Object.getOwnPropertyNames(a);
    var bKeys = Object.getOwnPropertyNames(b);
    if (aKeys.length!=bKeys.length)
        return false;
    aKeys.sort();
    bKeys.sort();
    for(var i=0; i<aKeys.length; i++)
        if (aKeys[i]!=bKeys[i]) // keys must be strings
            return false;
    return deepEquals(aKeys.map(k=>a[k]), aKeys.map(k=>b[k]));
}
function mapsEqual(a,b) {
    if (a.size!=b.size)
        return false;
    var aPairs = Array.from(a);
    var bPairs = Array.from(b);
    aPairs.sort((x,y) => x[0]<y[0]);
    bPairs.sort((x,y) => x[0]<y[0]);
    for(var i=0; i<a.length; i++)
        if (!deepEquals(aPairs[i][0],bPairs[i][0]) || !deepEquals(aPairs[i][1],bPairs[i][1]))
            return false;
    return true;
}
function typedArraysEqual(a,b) {
    a = new Uint8Array(a);
    b = new Uint8Array(b);
    if (a.length != b.length)
        return false;
    for(var i=0; i<a.length; i++)
        if (a[i]!=b[i])
            return false;
    return true;
}

Демо (не проверено):

var nineTen = new Float32Array(2);
nineTen[0]=9; nineTen[1]=10;
deepEquals(
    [[1,[2,3]], 4, {a:5,b:6}, new Map([['c',7],['d',8]]), nineTen],
    [[1,[2,3]], 4, {b:6,a:5}, new Map([['d',8],['c',7]]), nineTen]
)

(sidenote: Карты являются словарями es6. Я не могу сказать, имеют ли они производительность поиска O (1) или O (log (N)), но в любом случае они "упорядочены" в том смысле, что они отслеживают порядок в котором пары ключ-значение были вставлены в них. Однако семантика того, должны ли две Карты быть равными, если элементы были вставлены в них в другом порядке, неоднозначна. Ниже приведен пример реализации deepEquals, в котором две карты равны даже если элементы были вставлены в них в другом порядке.)

(примечание [1]: ВАЖНО: ЗАМЕЧАНИЕ О РАВЕНСТВЕ: Вы можете переопределить отмеченную строку пользовательским понятием равенства, которое вам также придется изменить в других функциях, где бы оно ни появлялось. Например, вы или нет? Вы хотите NaN == NaN? По умолчанию это не так. Есть еще более странные вещи, такие как 0 == '0'. Считаете ли вы два объекта одинаковыми, если и только если они являются одним и тем же объектом в память? См. fooobar.com/questions/7041/.... Вы должны задокументировать понятие равенства, которое вы используете.)

Вы должны быть в состоянии распространить вышесказанное на WeakMaps, WeakSets. Не уверен, имеет ли смысл распространяться на DataViews. Должен также иметь возможность распространяться на RegExps, вероятно, и т.д.

Расширяя его, вы понимаете, что делаете множество ненужных сравнений. Именно здесь может пригодиться функция type которую я определил ранее (решение № 2); тогда вы можете отправить мгновенно. Стоит ли это накладных расходов (возможно? Не знаю, как это работает под капотом) строки, представляющей тип, зависит от вас. Вы можете просто переписать диспетчер, то есть функцию deepEquals, что-то вроде:

var dispatchTypeEquals = {
    number: function(a,b) {...a==b...},
    array: function(a,b) {...deepEquals(x,y)...},
    ...
}
function deepEquals(a,b) {
    var typeA = extractType(a);
    var typeB = extractType(a);
    return typeA==typeB && dispatchTypeEquals[typeA](a,b);
}

Ответ 3

jQuery не имеет метода сравнения массивов. Однако библиотека поддеревьев > (или сопоставимая библиотека Lodash) имеет такой метод: isEqual, и он может обрабатывать множество других случаев (например, литералы объектов). Чтобы придерживаться приведенного примера:

var a=[1,2,3];
var b=[3,2,1];
var c=new Array(1,2,3);

alert(_.isEqual(a, b) + "|" + _.isEqual(b, c));

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

EDIT: Как уже отмечалось в комментариях, вышесказанное теперь работает только в том случае, если оба массива имеют свои элементы в одном порядке, то есть:

_.isEqual([1,2,3], [1,2,3]); // true
_.isEqual([1,2,3], [3,2,1]); // false

К счастью, у Javascript есть встроенный метод для решения этой точной проблемы, sort:

_.isEqual([1,2,3].sort(), [3,2,1].sort()); // true

Ответ 4

Для примитивных значений, таких как числа и строки, это простое решение:

a = [1,2,3]

b = [3,2,1]

a.sort().toString() == b.sort().toString() 

Вызов sort() гарантирует, что порядок элементов не имеет значения. Вызов toString() создаст строку со значениями, разделенными запятыми, чтобы обе строки могли быть проверены на равенство.

Ответ 5

С версией JavaScript 1.6 это просто:

Array.prototype.equals = function( array ) {
  return this.length == array.length && 
         this.every( function(this_i,i) { return this_i == array[i] } )  
  }

Например, [].equals([]) дает true, а [1,2,3].equals( [1,3,2] ) дает false.

Ответ 6

Даже если это показалось бы супер простым, иногда это действительно полезно. Если вам нужно только проверить, имеют ли два массива одинаковые элементы, и они находятся в одном порядке, попробуйте следующее:

[1, 2, 3].toString() == [1, 2, 3].toString()
true
[1, 2, 3,].toString() == [1, 2, 3].toString()
true
[1,2,3].toString() == [1, 2, 3].toString()
true

Однако это не работает для расширенных случаев в режиме, например:

[[1,2],[3]].toString() == [[1],[2,3]].toString()
true

Это зависит от того, что вам нужно.

Ответ 7

Основываясь на комментарии Тима Джеймса и комментария Fox32, следующее должно проверять наличие нулей, при условии, что два нуля не равны.

function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); }

> arrays_equal([1,2,3], [1,3,4])
false
> arrays_equal([1,2,3], [1,2,3])
true
> arrays_equal([1,3,4], [1,2,3])
false
> arrays_equal(null, [1,2,3])
false
> arrays_equal(null, null)
false

Ответ 8

jQuery имеет такой метод для глубокого рекурсивного сравнения.

Проверка общего уровня строгого равенства может выглядеть следующим образом:

function deepEquals(obj1, obj2, parents1, parents2) {
    "use strict";
    var i;
    // compare null and undefined
    if (obj1 === undefined || obj2 === undefined || 
        obj1 === null || obj2 === null) {
        return obj1 === obj2;
    }

    // compare primitives
    if (typeof (obj1) !== 'object' || typeof (obj2) !== 'object') {
        return obj1.valueOf() === obj2.valueOf();
    }

    // if objects are of different types or lengths they can't be equal
    if (obj1.constructor !== obj2.constructor || (obj1.length !== undefined && obj1.length !== obj2.length)) {
        return false;
    }

    // iterate the objects
    for (i in obj1) {
        // build the parents list for object on the left (obj1)
        if (parents1 === undefined) parents1 = [];
        if (obj1.constructor === Object) parents1.push(obj1);
        // build the parents list for object on the right (obj2)
        if (parents2 === undefined) parents2 = [];
        if (obj2.constructor === Object) parents2.push(obj2);
        // walk through object properties
        if (obj1.propertyIsEnumerable(i)) {
            if (obj2.propertyIsEnumerable(i)) {
                // if object at i was met while going down here
                // it a self reference
                if ((obj1[i].constructor === Object && parents1.indexOf(obj1[i]) >= 0) || (obj2[i].constructor === Object && parents2.indexOf(obj2[i]) >= 0)) {
                    if (obj1[i] !== obj2[i]) {
                        return false;
                    }
                    continue;
                }
                // it not a self reference so we are here
                if (!deepEquals(obj1[i], obj2[i], parents1, parents2)) {
                    return false;
                }
            } else {
                // obj2[i] does not exist
                return false;
            }
        }
    }
    return true;
};

Тесты:

// message is displayed on failure
// clean console === all tests passed
function assertTrue(cond, msg) {
    if (!cond) {
        console.log(msg);
    }
}

var a = 'sdf',
    b = 'sdf';
assertTrue(deepEquals(b, a), 'Strings are equal.');
b = 'dfs';
assertTrue(!deepEquals(b, a), 'Strings are not equal.');
a = 9;
b = 9;
assertTrue(deepEquals(b, a), 'Numbers are equal.');
b = 3;
assertTrue(!deepEquals(b, a), 'Numbers are not equal.');
a = false;
b = false;
assertTrue(deepEquals(b, a), 'Booleans are equal.');
b = true;
assertTrue(!deepEquals(b, a), 'Booleans are not equal.');
a = null;
assertTrue(!deepEquals(b, a), 'Boolean is not equal to null.');
a = function () {
    return true;
};
assertTrue(deepEquals(
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': 1.0
    },
    true]
], 
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': 1.0
    },
    true]
]), 'Arrays are equal.');
assertTrue(!deepEquals(
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': 1.0
    },
    true]
],
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': '1'
    },
    true]
]), 'Arrays are not equal.');
a = {
    prop: 'val'
};
a.self = a;
b = {
    prop: 'val'
};
b.self = a;
assertTrue(deepEquals(b, a), 'Immediate self referencing objects are equal.');
a.prop = 'shmal';
assertTrue(!deepEquals(b, a), 'Immediate self referencing objects are not equal.');
a = {
    prop: 'val',
    inside: {}
};
a.inside.self = a;
b = {
    prop: 'val',
    inside: {}
};
b.inside.self = a;
assertTrue(deepEquals(b, a), 'Deep self referencing objects are equal.');
b.inside.self = b;
assertTrue(!deepEquals(b, a), 'Deep self referencing objects are not equeal. Not the same instance.');
b.inside.self = {foo: 'bar'};
assertTrue(!deepEquals(b, a), 'Deep self referencing objects are not equal. Completely different object.');
a = {};
b = {};
a.self = a;
b.self = {};
assertTrue(!deepEquals(b, a), 'Empty object and self reference of an empty object.');

Ответ 9

Проверяйте каждое значение по циклу for после проверки размера массива.

function equalArray(a, b) {
    if (a.length === b.length) {
        for (var i = 0; i < a.length; i++) {
            if (a[i] !== b[i]) {
                return false;
            }
        }
        return true;
    } else {
        return false;
    }
}

Ответ 10

Используя map() и reduce():

function arraysEqual (a1, a2) {
    return a1 === a2 || (
        a1 !== null && a2 !== null &&
        a1.length === a2.length &&
        a1
            .map(function (val, idx) { return val === a2[idx]; })
            .reduce(function (prev, cur) { return prev && cur; }, true)
    );
}

Ответ 11

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

В вашем вопросе вы указываете на то, что хотите игнорировать порядок значений в массиве. Мое решение по сути не делает этого, но вы можете достичь этого, сортируя массивы перед сравнением для равенства

Я также хотел, чтобы вариант литья не-объектов в строки, чтобы [1,2] === [ "1", 2]

Поскольку мой проект использует UnderscoreJs, я решил сделать его mixin, а не автономной функцией.

Вы можете проверить это на http://jsfiddle.net/nemesarial/T44W4/

Вот мой mxin:

_.mixin({
  /**
  Tests for the equality of two variables
    valA: first variable
    valB: second variable
    stringifyStatics: cast non-objects to string so that "1"===1
  **/
  equal:function(valA,valB,stringifyStatics){
    stringifyStatics=!!stringifyStatics;

    //check for same type
    if(typeof(valA)!==typeof(valB)){
      if((_.isObject(valA) || _.isObject(valB))){
        return false;
      }
    }

    //test non-objects for equality
    if(!_.isObject(valA)){
      if(stringifyStatics){
        var valAs=''+valA;
        var valBs=''+valB;
        ret=(''+valA)===(''+valB);
      }else{
        ret=valA===valB;
      }
      return ret;
    }

    //test for length
    if(_.size(valA)!=_.size(valB)){
      return false;
    }

    //test for arrays first
    var isArr=_.isArray(valA);

    //test whether both are array or both object
    if(isArr!==_.isArray(valB)){
      return false;
    }

    var ret=true;
    if(isArr){
      //do test for arrays
      _.each(valA,function(val,idx,lst){
        if(!ret){return;}
        ret=ret && _.equal(val,valB[idx],stringifyStatics);
      });
    }else{
      //do test for objects
      _.each(valA,function(val,idx,lst){
        if(!ret){return;}

        //test for object member exists
        if(!_.has(valB,idx)){
          ret=false;
          return;
        }

        // test for member equality
        ret=ret && _.equal(val,valB[idx],stringifyStatics);
      });

    }
    return ret;
  }
});

Вот как вы его используете:

_.equal([1,2,3],[1,2,"3"],true)

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

_.equal(
    ['a',{b:'b',c:[{'someId':1},2]},[1,2,3]],
    ['a',{b:'b',c:[{'someId':"1"},2]},["1",'2',3]]
,true);

Ответ 12

Если вы хотите проверить массивы объектов на равенство, и порядок не имеет значения, т.е.

areEqual([{id: "0"}, {id: "1"}], [{id: "1"}, {id: "0"}]) // true

вам нужно сначала отсортировать массивы. lodash содержит все необходимые инструменты, объединив sortBy и isEqual:

// arr1 & arr2: Arrays of objects 
// sortProperty: the property of the object with which you want to sort
// Note: ensure every object in both arrays has your chosen sortProperty
// For example, arr1 = [{id: "v-test_id0"}, {id: "v-test_id1"}]
// and          arr2 = [{id: "v-test_id1"}, {id: "v-test_id0"}]
// sortProperty should be 'id'

function areEqual (arr1, arr2, sortProperty) {
  return _.areEqual(_.sortBy(arr1, sortProperty), _.sortBy(arr2, sortProperty))
}

EDIT: Поскольку sortBy возвращает новый массив, вам не нужно клонировать ваши массивы перед сортировкой. Исходные массивы не будут мутированы.

Обратите внимание, что для lodash isEqual порядок имеет значение. В приведенном выше примере возвращается false, если sortBy не применяется к каждому массиву в первую очередь.

Ответ 13

Если вы используете lodash и не хотите изменять любой массив, вы можете использовать функцию _.xor(). Он сравнивает два массива как множества и возвращает набор, содержащий их разницу. Если длина этой разности равна нулю, эти два массива по существу равны:

var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);
_.xor(a, b).length === 0
true
_.xor(b, c).length === 0
true

Ответ 14

Он обрабатывает все возможные вещи и даже ссылается на структуру объекта. Вы можете увидеть пример в конце кода.

var deepCompare = (function() {
    function internalDeepCompare (obj1, obj2, objects) {
        var i, objPair;

        if (obj1 === obj2) {
            return true;
        }

        i = objects.length;
        while (i--) {
            objPair = objects[i];
            if (  (objPair.obj1 === obj1 && objPair.obj2 === obj2) ||
                  (objPair.obj1 === obj2 && objPair.obj2 === obj1)  ) {                          
                return true;
            }                    
        }
        objects.push({obj1: obj1, obj2: obj2});

        if (obj1 instanceof Array) {
            if (!(obj2 instanceof Array)) {
                return false;
            }

            i = obj1.length;

            if (i !== obj2.length) {
               return false; 
            }

            while (i--) {
                if (!internalDeepCompare(obj1[i], obj2[i], objects)) {
                    return false;
                }
            }
        }
        else {
            switch (typeof obj1) {
                case "object":                
                    // deal with null
                    if (!(obj2 && obj1.constructor === obj2.constructor)) {
                        return false;
                    }

                    if (obj1 instanceof RegExp) {
                        if (!(obj2 instanceof RegExp && obj1.source === obj2.source)) {
                            return false;
                        }
                    }                 
                    else if (obj1 instanceof Date) {
                        if (!(obj2 instanceof Date && obj1.getTime() === obj2.getTime())) {
                            return false;
                        }
                    } 
                    else {    
                        for (i in obj1) {
                            if (obj1.hasOwnProperty(i)) {       
                                if (!(obj2.hasOwnProperty(i) && internalDeepCompare(obj1[i], obj2[i], objects))) {
                                    return false;
                                }
                            }
                        }         
                    }
                    break;
                case "function": 
                    if (!(typeof obj2 === "function" && obj1+"" === obj2+"")) {
                        return false;
                    }
                    break;
                default:                 //deal with NaN 
                    if (obj1 !== obj2 && obj1 === obj1 && obj2 === obj2) {
                        return false;            
                    }
            }
        }

        return true;
    }

    return function (obj1, obj2) {
        return internalDeepCompare(obj1, obj2, []);    
    };
}());

/*    
var a = [a, undefined, new Date(10), /.+/, {a:2}, function(){}, Infinity, -Infinity, NaN, 0, -0, 1, [4,5], "1", "-1", "a", null],
    b = [b, undefined, new Date(10), /.+/, {a:2}, function(){}, Infinity, -Infinity, NaN, 0, -0, 1, [4,5], "1", "-1", "a", null];
deepCompare(a, b);
*/

Ответ 15

Этот метод отстой, но я оставил его здесь для справки, чтобы другие избегали этого пути:


Использование опции 1 от @ninjagecko наилучшим образом помогло мне:

Array.prototype.equals = function(array) {
    return array instanceof Array && JSON.stringify(this) === JSON.stringify(array) ;
}

a = [1, [2, 3]]
a.equals([[1, 2], 3]) // false
a.equals([1, [2, 3]]) // true

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

Ответ 16

var a= [1, 2, 3, '3'];
var b = [1, 2, 3];

var c = a.filter(function (i) { return ! ~b.indexOf(i); });

alert(c.length);