48

I started with:

"1:2".split(':') == ["1","2"]; 
// false

Then tried:

[1,2] == [1,2];
// false

and ultimately:

[] == []; 
// false

I've since found that:

"1:2".split(':').toString() == [1,2].toString();
// true

So I've solved my initial issue (kind of) but why can't arrays match each other?

Shubham Khatri
  • 246,420
  • 52
  • 367
  • 373
Jacksonkr
  • 30,630
  • 38
  • 174
  • 276
  • 3
    Neither `==`, nor `===` do element wise comparison. They both check if both the arrays are one and the same. – thefourtheye Jun 13 '15 at 15:57
  • 2
    This is because arrays are objects in JavaScript. You might want to have a look at this http://stackoverflow.com/questions/22395357/how-to-compare-two-arrays-are-equal-using-javascript-or-jquery – ankur Jun 13 '15 at 15:58
  • 1
    possible duplicate of [Why isn't `[1,2,3]` equal to itself in Javascript?](https://stackoverflow.com/q/7314635/1048572) – Bergi May 04 '18 at 16:22
  • Note if you just want to check for an empty array you can check if `array.length === 0` – nCardot Sep 06 '21 at 18:44

7 Answers7

52

Javascript arrays are objects and you can't simply use the equality operator == to understand if the content of those objects is the same. The equality operator will only test if two object are actually exactly the same instance (e.g. myObjVariable==myObjVariable, works for null and undefined too).

If you need to check if two array are equals i'd recommend to just traverse both arrays and verify that all the elements have the same value (and that the two array have the same length).

Regarding custom objects equality i'd build instead a specific equals function and i'd add it to the prototype of your class.

Considering that in the end you converted both arrays to a String and tested equality of the resulting strings, you could one day consider using a similar but more generic technique you'll find described in more than a few places:

JSON.stringify(OBJ1) === JSON.stringify(OBJ2) 

Well, don't.

While this could work if the order of the properties will always the same for those object instances, this leaves the door open for extremely nasty bugs that could be hard to track down. Always favor a more explicit approach and just write a clean and readable function that will test for equality checking all the required fields.

uraimo
  • 17,617
  • 8
  • 45
  • 55
  • Interesting note, `myObjVariable == myObjectVariable` is true in all instances of JS except where `myObjVariable = NaN`... :) – War10ck May 03 '18 at 20:21
  • 1
    there's many interesting notes about NaN, one of the most famous being `NaN.constructor === Number`. – Dmitry May 03 '18 at 20:22
13

The == operator for Objects in Javascript only checks to see if the objects are the same actual object reference, not if they are two separate object that contain the same contents. There is no built in operator for checking if they contain the same contents. You would have to write a function to do that sort of comparison yourself.

Your string conversion is one way of comparing two arrays as long as the array elements only contain primitive values (not other objects). If the array elements could contain other elements, then you would have to make sure those objects were themselves converted into representative strings too.

And, converting to a string would not discern between an array element that contains "4" versus one that contains 4 since both convert to "4" in the string representation.

jfriend00
  • 637,040
  • 88
  • 896
  • 906
3

Equality for objects will tell you if the two objects are the same one.

var a = [];
var b = a;
a === b;    // True, a and b refer to the same object
[] === [];  // False, two separate objects

You will have to loop through the arrays to see if they have the same elements.

See: How to check if two arrays are equal with JavaScript?

Community
  • 1
  • 1
folkol
  • 4,639
  • 22
  • 25
2

In javascript each [] is an instance of window.Array class. So you are basically trying to compare two different objects. Since array's can have any no. and any type of elements including Objects and Custom Objects and those nested arrays can again have numerous properties and arrays and so on.

It becomes ambiguous when it comes to comparison, you will never be sure what do you want to do with those objects and nested properties. So what you are trying to achieve by comparing can be done in so many other ways. You just have to figure out the right way for your case.

Vinay Aggarwal
  • 1,457
  • 1
  • 10
  • 19
1

One way is to make your own Array checking function:

How to compare arrays in JavaScript?!

Another way is to convert the Array to a String with .join(), and compare the strings. Then convert them back into Arrays with .split().

Community
  • 1
  • 1
clickbait
  • 2,602
  • 1
  • 23
  • 54
-1

My guess is that because when javascript was designed, they thought element wise comparison was a rarely used feature so it was never put into the language.

This feature is fairly rare in popular languages; Java doesn't support it, C# doesn't support it, C++ stl types don't support it.

element wise comparison is fairly expensive and complicated compared to reference comparison.

In a perfect world, everything can be compared by reference, so that every two objects that have the same state would have the same reference, allowing us to really cheaply check for equality, by just comparing their internal virtual addresses with a simple number comparison.

Unfortunately, we don't live in a perfect world, and the above is only possible for strings with a string pool, along with few other relatively memory expensive caching options.

Some languages like Prolog and Haskell allow comparison by value; eg

myProgram :- 
    Object1 = [1, "something", true, [1,[[], []], true,[false]]],
    Object2 = [1, "something", false, [1,[[], []], true,[false]]],
    Object3 = [1, "something", true, [1,[[], []], true,[false]]],
    Object4 = [1, "something", false, [1,[[], []], true,[false]]],
    (Object1 = Object2 
        -> write("first test passed.")    
        ; write("first test failed\n")),
    (Object1 = Object3 
        -> write("second test passed!\n")
        ; write("second test failed!\n")),
    (Object2 = Object4
        -> write("third test passed!\n")
        ; write("third test failed!")).

You can implement your own deep-comparator in any language by using a map from constructor to a comparator for that constructor. Since JavaScript doesn't have maps from anything but string to object, and javascript clients do not have access to the internal unique identifier of objects, we need to use a table with constructor, comparator pairs, something like below.

class MyList {
    constructor(a, b) {
        this.head_ = a;
        this.tail_ = b;
    }
    getHead() {
        return this.head_;
    }
    getTail() {
        return this.tail_;
    }
    setHead(x) {
        this.head_ = x;
    }
    setTail(x) {
        this.tail_ = x;
    }
    equals(other) {
        if (typeof other !== 'object') {
            console.log(other, 'EEP');
            return false;
        }
        if (!(other instanceof MyList)) {
            console.log(other, 'EEP');
            return false;
        }

        var h = this.head_;
        var ho = other.getHead();
        var cmp1 = comparatorof(h);
        if (!cmp1(h, ho)) {
            return false;
        }
        var t = this.tail_;
        var to = other.getTail();
        var cmp2 = comparatorof(t);
        if (!cmp2(t, to)) {
            return false;
        }

        return true;
    }
}

var object1 = {
    0: "one",
    1: "two",
    2: ["one", "two", []],
    something: {
        1: [false, true]
    }
};

function strictComparator(a, b) {
    return a === b;
}

// given any object, tries finding a function for comparing 
// that object to objects of the same kind. Kind being
// used loosely, since some objects like null resist being categorized,
// so these objects need special alteration of the comparatorof itself.
function comparatorof(x) {
    if (x === null || x === undefined) {
        return strictComparator;
    }

    x = Object(x); // promote primitives to objects
    var ctor = x.constructor;
    var c2ct = ctorToComparatorTable;
    var n = c2ct.length;

    for (var i = 0; i < n; ++i) {
        var record = c2ct[i];
        var keyCtor = record[0];

        if (keyCtor === ctor) {
            return record[1];
        }
    }
    throw new TypeError('no comparator exists for ' + x);
}

var ctorToComparatorTable = [
    [String, function(a, b) {
        return a == b;
    }],
    [Object, function(a, b) {
        for (var key in a) {
            var avalue = a[key];
            var bvalue = b[key];
            var cmp = comparatorof(avalue);

            if (!cmp(avalue, bvalue)) {
                return false;
            }
        }

        return true;
    }],
    [Number, function(a, b) {
        return a == b;
    }],
    [Boolean, function(a, b) {
        return a == b;
    }],
    [Array, function(as, bs) {
        if (typeof bs !== 'object') {
            return false;
        }
        var nAs = as.length;
        var nBs = bs.length;

        if (nAs !== nBs) {
            return false;
        }

        for (var i = 0; i < nAs; ++i) {
            var a = as[i];
            var b = bs[i];
            var cmp = comparatorof(a);

            if (!cmp(a, b)) {
                return false;
            }
        }

        return true;
    }],
    [MyList, function(a, b) {
        return a.equals(b);
    }]
];

// true
console.log(comparatorof([])([new MyList(1, new MyList(2, 3))], [new MyList(1, new MyList(2, 3))]));
// true
console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(2, 3))]));
// false
console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(3, 3))]));
// true
console.log(comparatorof({})({
    1: 'one',
    one: '1',
    x: new MyList(1, {})
}, {
    1: 'one',
    one: '1',
    x: new MyList(1, {})
}));
// true
console.log(comparatorof(2)(
    3,
    3
));
//true
console.log(comparatorof(true)(
    true,
    true
));
//false
console.log(comparatorof([])(
    [1, 2, new MyList(1, 2)], [1, 2, new MyList(4, 9)]
));
// true
console.log(comparatorof([])(
    [1, 2, new MyList(1, 2), null], [1, 2, new MyList(1, 2), null]
));
// false
console.log(comparatorof(null)(
    null,
    undefined
));
// true
console.log(comparatorof(undefined)(
    undefined,
    undefined
));
// true
console.log(comparatorof(null)(
    null,
    null
));

One big issue is that ES6 is already full of features that are incompatible with JScript and Nashorn JJS as well as ActionScript that the language may as well be rebranded as a whole new language every few months, considering that's effectively what you get when you add new features to a language that break compatibility with old versions of it that cannot be replicated without an extra eval layer.

This problem goes back a long time where on one side you have a minimal language like Lisp which is "easier"(still can't overload ' operator) to introduce "first class" features without breaking backward compatibility, and then you have languages like Perl which cannot be extended with new first-class keywords without an extra eval layer. JavaScript chose the second approach and generally bypasses the consequences by using helper objects like Math, Object to introduce new features, but anytime it wants to add "first class constructs" it ends up breaking backward compatibility.

As a proof of concept, In Lisp you can overload == operator, whereas in JavaScript you can't, and in Perl you can but through a mechanism that reserves keywords.

Dmitry
  • 4,752
  • 4
  • 35
  • 48
  • 1
    *“because when javascript was designed, they thought element wise comparison was a rarely used feature so it was never put into the language.”* Citation needed. – Ry- Jul 22 '18 at 19:20
  • dang it i knew somebody would catch me making that up. I was making a guess since it is an additional language feature that i can't think of any other scripting language at the time offering. Very few languages offer list matching at a language level and it causes a bit of confusion because c like languages generally work by reference comparisons rather than value comparisons. Great catch though, I'll rephrase it to be more charitable later. – Dmitry Jul 22 '18 at 20:17
-2

If I relate this problem with that in Python:

Input:

a="1 2 3 4"

case I:

a=input.split(' ')

output: ['1', '2', '3', '4']

case II:

a=map(int,input.split(' '))

output: [1, 2, 3, 4]

So, the fault is that of type, as it could come-out aa 'true' for:

"1:2".split(':').toString() == [1,2].toString(); //true
Ank_247shbm
  • 424
  • 6
  • 17