如何检查两个数组是否与JavaScript相同?

How to check if two arrays are equal with JavaScript?

本问题已经有最佳答案,请猛点这里访问。
1
2
3
4
5
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< >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,但它们都转换为json表示null,并被认为是相等的:好的。

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

(如果数组包含对象,这可能不起作用。这是否仍然适用于对象取决于JSON实现是否对键进行排序。例如,{1:2,3:4}的json可以等于,也可以不等于{3:4,1:2}的json,这取决于实现情况,规范对此不作任何保证。[2017更新:事实上,ES6规范现在保证对象键将按照1)整数属性,2)按定义顺序迭代属性,然后3)按定义顺序迭代符号属性。因此,如果json.stringify实现遵循这一点,那么相等的对象(在==意义上,但不一定在==意义上)将串接为相等的值。需要更多的研究。所以我猜你可以用相反的顺序复制一个具有属性的对象,但我不能想象它是偶然发生的…]至少在chrome上,json.stringify函数倾向于按照定义的顺序返回键(至少我注意到了),但这种行为在任何时候都会发生变化,并且不应该依赖。.如果您选择不使用列表中的对象,这应该可以正常工作。如果列表中的对象都具有唯一的ID,则可以执行a1.map(function(x)}{return {id:x.uniqueId}})。如果列表中有任意对象,可以继续阅读选项2。)好的。

这也适用于嵌套数组。好的。

但是,由于创建这些字符串和垃圾收集字符串的开销,它的效率稍低。好的。

选项2好的。

更多"正确"选项,您可以覆盖它来处理特殊情况(如常规对象、空/未定义对象和自定义对象,如果您愿意的话):好的。

1
2
3
4
5
6
7
8
9
10
11
// 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]})
    });
}

nbsp;好的。

1
2
3
4
5
6
7
8
9
10
11
12
// 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});

nbsp;好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

演示:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

要像使用常规函数一样使用此函数,请执行以下操作:好的。

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

演示:好的。

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

选项3好的。

编辑:现在是2016年,我以前的回答过于复杂,让我心烦。这种递归的、命令式的"递归编程101"实现使代码非常简单,而且在最早可能的时候失败(给我们效率)。它也不会生成多余的临时数据结构(一般来说,函数编程没有任何问题,只是保持这里的整洁)。好的。

如果我们想将此应用于非空数组,我们可以执行seriesofarrays.reduce(arraysequal)。好的。

这是它自己的函数,而不是使用object.defineproperties附加到array.prototype,因为如果我们传入一个未定义的值(如果您想这样做,这是一个很好的设计决策),这将失败,并出现键错误。好的。

这只回答操作系统的原始问题。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
    }
}

实例:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

如果您想将此应用于具有JS对象的类似JSON的数据结构,可以这样做。幸运的是,我们保证所有对象的键都是唯一的,所以遍历对象本身的属性并按键对它们排序,然后断言排序后的键数组是相等的,值数组是相等的,并且只是递归的。我们也可以扩展它来包含地图(其中键也是唯一的)。(然而,如果我们把它扩展到集合,我们会遇到树同构问题http://logic.pdmi.ras.ru/~smal/files/smal_jass08_slides.pdf-幸运的是,它不像一般的图同构那样困难;实际上有一个O(顶点)算法来解决它,但是有效地解决它会变得非常复杂。病理学的情况是,如果你有一套由许多看似不可辨别的物体组成的装置,但进一步检查后,这些物体中的一些可能会随着你深入研究它们而有所不同。您还可以通过使用散列来拒绝几乎所有的情况来解决这个问题。)好的。

选项4:(续2016年版)好的。

这应该适用于大多数对象:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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;
}

演示(未经广泛测试):好的。

1
2
3
4
5
6
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]
)

(旁注:地图是ES6字典。我不知道它们是否具有O(1)或O(log(n))查找性能,但在任何情况下,它们都是"有序的",因为它们跟踪插入键值对的顺序。但是,如果元素以不同的顺序插入到两个映射中,那么两个映射是否应该相等的语义是不明确的。我在下面给出了一个deepequals的示例实现,该deepequals认为两个映射是相等的,即使元素以不同的顺序插入它们。)好的。

(注[1]:重要提示:平等的概念:您可能希望用一个自定义的平等概念来覆盖所标注的行,在它出现的任何地方,您还必须更改其他函数。例如,是否要NaN==NaN?默认情况下,情况并非如此。还有更奇怪的事情,比如0='0'。如果并且仅当两个对象在内存中是同一个对象时,您认为它们是相同的吗?请参阅https://stackoverflow.com/a/5447170/711085。你应该记录下你所使用的平等的概念。)好的。

您应该能够将上述扩展到weakmaps、weaksets。不确定扩展到数据视图是否有意义。还应该能够扩展到regexps,可能等等。好的。

当你扩展它时,你会意识到你做了很多不必要的比较。这就是我之前定义的type函数(解决方案2)可以使用的地方,然后您可以立即调度。这是否值得(可能的)管理费用?不确定它在引擎盖下是如何工作的)表示类型的字符串由您决定。然后,您可以重写Dispatcher,即函数deepEquals,使其类似于:好的。

1
2
3
4
5
6
7
8
9
10
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,它还可以处理各种其他情况(如对象文本)。要坚持提供的示例:

1
2
3
4
5
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的一个很好的补充。

编辑:正如注释中所指出的,只有当两个数组的元素顺序相同时,上面的内容才有效,即:

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

幸运的是,javascript有一个内置的方法来解决这个确切的问题,sort

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


对于像数字和字符串这样的基元值,这是一个简单的解决方案:

1
2
3
4
5
a = [1,2,3]

b = [3,2,1]

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

调用sort()将确保元素的顺序无关紧要。toString()调用将创建一个值为逗号分隔的字符串,以便测试两个字符串是否相等。


使用1.6版的javascript,就这么简单:

1
2
3
4
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
4
5
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
[[1,2],[3]].toString() == [[1],[2,3]].toString()
true

这取决于你需要什么。


根据TimJamesAnswer和Fox32的评论,下面应该检查空值,假设两个空值不相等。

1
2
3
4
5
6
7
8
9
10
11
12
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有这样的方法来进行深度递归比较。

国内通用的严格平等检查可以如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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's 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's 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;
};

测验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 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循环检查每个值。

1
2
3
4
5
6
7
8
9
10
11
12
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()时:

1
2
3
4
5
6
7
8
9
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]

因为我的项目使用了下划线,所以我决定将它作为一个混合函数,而不是一个独立的函数。

你可以在http://jsfiddle.net/nemesarial/t44w4上测试它。/

这是我的MXIN:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
_.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;
  }
});

这就是你如何使用它:

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

要演示嵌套,可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
_.equal(
    ['a',{b:'b',c:[{'someId':1},2]},[1,2,3]],
    ['a',{b:'b',c:[{'someId':"1
<p><center>[wp_ad_camp_3]</center></p><hr><P>如果您希望检查对象数组的相等性和顺序并不重要,即</P><P><wyn>areequal([id:"
0<hr><P>如果您使用的是lodash并且不想修改任何一个数组,那么可以使用函数uxor()。它将两个数组作为集合进行比较,并返回包含差异的集合。如果此差的长度为零,则两个数组基本上相等:</P>[cc lang="javascript"]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

It handle all possible stuff and even reference itself in structure of object. You can see the example at the end of code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
2
3
4
5
6
var a= [1, 2, 3, '3'];
var b = [1, 2, 3];

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

alert(c.length);

这个方法很糟糕,但我把它留在这里作为参考,所以其他人会避开这条路径:

使用@ninjageckeco的选项1对我来说效果最好:

1
2
3
4
5
6
7
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

它还将处理空值和未定义的大小写,因为我们要将其添加到数组的原型中,并检查另一个参数是否也是数组。