var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);
alert(a == b + "|" + b == c);
Как проверить этот массив на равенство и получить метод, который возвращает true
, если они равны?
Предлагает ли jQuery какой-либо метод для этого?
var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);
alert(a == b + "|" + b == c);
Как проверить этот массив на равенство и получить метод, который возвращает true
, если они равны?
Предлагает ли jQuery какой-либо метод для этого?
Это то, что вы должны сделать. Пожалуйста, не используйте 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;
}
Опция 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);
}
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
Для примитивных значений, таких как числа и строки, это простое решение:
a = [1,2,3]
b = [3,2,1]
a.sort().toString() == b.sort().toString()
Вызов sort()
гарантирует, что порядок элементов не имеет значения. Вызов toString()
создаст строку со значениями, разделенными запятыми, чтобы обе строки могли быть проверены на равенство.
С версией 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
.
Даже если это показалось бы супер простым, иногда это действительно полезно. Если вам нужно только проверить, имеют ли два массива одинаковые элементы, и они находятся в одном порядке, попробуйте следующее:
[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
Это зависит от того, что вам нужно.
Основываясь на комментарии Тима Джеймса и комментария 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
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.');
Проверяйте каждое значение по циклу 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;
}
}
Используя 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)
);
}
Нет простого способа сделать это. Мне тоже это нужно, но мне нужна функция, которая может принимать любые две переменные и проверять равенство. Это включает в себя значения, отличные от объекта, объекты, массивы и любой уровень вложенности.
В вашем вопросе вы указываете на то, что хотите игнорировать порядок значений в массиве. Мое решение по сути не делает этого, но вы можете достичь этого, сортируя массивы перед сравнением для равенства
Я также хотел, чтобы вариант литья не-объектов в строки, чтобы [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);
Если вы хотите проверить массивы объектов на равенство, и порядок не имеет значения, т.е.
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
не применяется к каждому массиву в первую очередь.
Если вы используете 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
Он обрабатывает все возможные вещи и даже ссылается на структуру объекта. Вы можете увидеть пример в конце кода.
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);
*/
Этот метод отстой, но я оставил его здесь для справки, чтобы другие избегали этого пути:
Использование опции 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, так как мы добавляем это в прототип массива и проверяем, что другой аргумент также является массивом.
var a= [1, 2, 3, '3'];
var b = [1, 2, 3];
var c = a.filter(function (i) { return ! ~b.indexOf(i); });
alert(c.length);