10

I need a function:

function isSame(a, b){
} 

In which, if a and b are the same, it returns true.
, I tried return a === b, but I found that [] === [] will return false.
Some results that I expect this function can gave:

isSame(3.14, 3.14);  // true  
isSame("hello", "hello"); // true  
isSame([], []); // true  
isSame([1, 2], [1, 2]); // true  
isSame({ a : 1, b : 2}, {a : 1, b : 2}); //true  
isSame([1, {a:1}], [1, {a:1}]);  //true
wong2
  • 34,358
  • 48
  • 134
  • 179
  • 5
    Do you really expect `isSame([1, 2], [2, 1]);` to be true? Arrays are ordered. These are not the same. – jtbandes Jul 14 '11 at 06:30
  • @jtbandes I forgot that, thanks – wong2 Jul 14 '11 at 06:37
  • http://stackoverflow.com/questions/201183/how-do-you-determine-equality-for-two-javascript-objects please google first before asking :) –  Jul 14 '11 at 06:44
  • @Pez: he wants probably a custom function that does a little more than just `return a === b;` – Salman A Jul 14 '11 at 06:46
  • @wong2 - do you mean for your isSame() to return true if a and b both refer to the same object, or to return true if they refer to different objects but those objects have the same number of properties with the same property names and values? Same prototype too? This has been discussed before - see, e.g., http://stackoverflow.com/q/201183/615754 – nnnnnn Jul 14 '11 at 06:50

5 Answers5

12

You could embed Underscore.js and use _.isEqual(obj1, obj2). The function works for arbitrary objects and uses whatever is the most efficient way to test the given objects for equality.

thirtydot
  • 224,678
  • 48
  • 389
  • 349
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • +1 - This is especially relevant to me since I'm not very familiar with Underscore, but I'm using Meteor (which comes with _). – Dom Ramirez Sep 23 '13 at 01:25
10

the best way to do that is to use a JSON serializer. serialize both to string and compare the string.

TheBrain
  • 5,528
  • 2
  • 25
  • 26
  • 4
    What if the items in an array are ordered differently? The lists contain the same elements, but they won't look the same once serialized. – svanryckeghem Jul 14 '11 at 06:50
  • 2
    @svanryckeghem they are not the same if they are in different order. Arrays are ordered collections – Raynos Jul 14 '11 at 06:55
  • 1
    @TheBrain - What if the objects contain methods? A JSON serialiser isn't going to handle that. Also, non-array objects don't really have an order for their properties, so may not result in the same JSON string (unless you write a JSON serialiser that explicitly sorts them). Finally, are two objects with the same set of name/value properties equal if they have different prototypes? – nnnnnn Jul 14 '11 at 07:16
  • @Raynos - It depends what "same" means to you. As a developer, I might want to know whether they are strictly the same, or whether they are equivalent. It's a question of semantics, not nature. It's not much different from knowing whether two objects are equal by reference, or by value. – svanryckeghem Jul 14 '11 at 07:18
  • @svanryckeghem then implement `eq`, `eql` and `equal` – Raynos Jul 14 '11 at 07:22
  • 1
    my solution was for the case where you want to test if two objects are the same. that means they have the same properties in the same order with the same values. if something, anything is changed then they are not the same. for all the examples you gave in your question, the serialization works. – TheBrain Jul 14 '11 at 08:40
  • order shouldn't matter for objects – Muhammad Umer Mar 03 '15 at 17:32
  • `JSON.stringify()` doesn't guarantee consistent ordering of object properties (usually it's the order the properties were set), so comparing two stringified objects won't always work. More here... https://stackoverflow.com/questions/16167581/sort-object-properties-and-json-stringify – chichilatte Sep 20 '18 at 16:20
4

There are some examples, adapted from scheme, on Crockford's site. Specifically, check out:

function isEqual(s1, s2) {
    return isAtom(s1) && isAtom(s2) ? isEqan(s1, s2) :
            isAtom(s1) || isAtom(s2) ? false :
            isEqlist(s1, s2);
}

It can all be found here:

http://javascript.crockford.com/little.js

Here is a working example:

http://jsfiddle.net/FhGpd/

Update:

Just wrote some test cases based on the OP. Turns out I needed to modify the sub1 function to check <= 0 not === 0 otherwise isEqual(3.14, 3.14) blew the stack. Also, isEqual does not work for object comparison, so you are on your own there. However, if you follow the examples on Crockford's site you will see how easy and fun it is to write recursive methods that could be used to check for object equality.

Community
  • 1
  • 1
Adam
  • 12,236
  • 9
  • 39
  • 44
0

If anyone reading this answer is using Angular.js, you can use angular.equals(obj1,obj2);

According to the docs:

Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and objects. Two objects or values are considered equivalent if at least one of the following is true:

  • Both objects or values pass === comparison.
  • Both objects or values are of the same type and all of their properties are equal by comparing them with angular.equals.
  • Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal).
  • Both values represent the same regular expression (In JavaScript, /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual representation matches).
  • During a property comparison, properties of function type and properties with names that begin with $ are ignored.

Scope and DOMWindow objects are being compared only by identify (===).

Jayant Bhawal
  • 2,044
  • 2
  • 31
  • 32
0

Here is something that can work:

function isSame(obj1, obj2, prefer){
// Optional parameter prefer allows to only check for object keys and not both keys and values of an object
var obj_prefer = prefer || "both"; 
function checkArray(arr1, arr2){
    for(var i = 0, j = obj1.length; i<j; i++){
        if(obj1[i] !== obj2[i]){return false;}
    }
    return true;
}

function checkValues(obj_1, obj_2){
    for(var prop in obj_1){
        if(typeof obj_1[prop] === "function"){  // converting functions to string so that they can be matched
            obj_1[prop] = String(obj_1[prop]);
            obj_2[prop] = String(obj_2[prop]);
        }

        if(obj_1[prop] !== obj_2[prop]){ return false;}
    }
    return true;
}
// The built in === will check everything except when typeof object is "object"
if ( typeof obj1 === "object"){
    // typeof Array is object so this is an alternative
    if((typeof obj1.push === "function") && (!obj1.hasOwnProperty('push'))){
        return checkArray(obj1, obj2);
        }

    else{
            if( obj_prefer !== "keys"){   // do not check for values if obj_prefer is "keys"
                return checkValues(obj1, obj2);
            }
            var keys_1 = Object.keys(obj1);
            var keys_2 = Object.keys(obj2);
            if(!checkArray(keys_1, keys_2)){return false;}

            return true;
    }
}

    // I thought undefined === undefined will give false but it isn't so you can remove it    
    if( typeof obj1 === "undefined" && typeof obj2 === "undefined" ){return true}

    if(typeof obj1 === "function"){
        return String(obj1) === String(obj2);
    }

        return obj1 === obj2;
}
console.log(isSame(2, 2));  //true
console.log(isSame([1], [1])); // true

Since it converts Functions into Strings to compare them, check out for spaces as that can break things:

var func1 = function(){},
    func2 = function(){ }; // function with extra space
isSame(func1, func2); // false

You can check out http://jsfiddle.net/webholik/dwaLN/4/ to try it yourself.

Ankit
  • 423
  • 2
  • 12