I have this:
var g = [{a:'a'},{a:'2'},{a:'3'}]
var c = [{a:'4'},{a:'2'},{a:'5'}]
The following statement:
g[1] == c[1]
Returns false, even though the objects look the same. Is there any way I can compare them literally so it will return me true instead of false?
You could encode them as JSON:
JSON.stringify(g[1]) == JSON.stringify(c[1])
You might also be interested in the answers to this related question on identifying duplicate Javascript objects.
For a more complex option, you might look at the annotated source code for Underscore's _.isEqual() function (or just use the library).
The == operator checks for reference equality. The only way to do what you want would be a memberwise equality test on the objects.
This ought to work:
function memberwiseEqual(a, b) {
if(a instanceof Object && b instanceof Object) {
for(key in a)
if(memberwiseEqual(a[key], b[key]))
return true;
return false;
}
else
return a == b;
}
Be wary of cases like these:
var a = {};
a.inner = a; //recursive structure!
here you compare the reference in the memory ,not its value try this and you will get true :
g[1]['a'] === c[1]['a']
In JavaScript variables which are objects (including arrays) are actually references to the collection. So when you write var x = { a: 2 } and var y = { a: 2 } then x and y become references to two different objects. So x will not equal y. But, if you did y = x then they would (because they would share the same reference). But then if you altered either object the other would be altered too.
So, when dealing with objects and arrays, by saying == you are checking if the two references are the same. In this case they are not.
Related
As someone used to python and C++, having an = copy objects by reference rather than value is not intuitive at all. Not just that, but there seems to be no direct way of copying objects to begin with. JSON.parse(JSON.stringify) is the closest option (if I know correctly), and even that has problems.
a) In a language where all variables are anyway treated as objects, why does the = operator distinguish between primitive and non-primitive data types to decide whether to copy by value or reference?
b) Why is copy by value not possible for objects?
c) What techniques are helpful for a beginner used to copying objects by value to code without it?
a) In a language where all variables are anyway treated as objects,
why does the = operator distinguish [...] ?
The =(assign) operator does not distinguish between primitive and non primitive data types. It kinda does the same for both, considering that equality is preserved after assignment (excluding exceptions e.g. NaN, ...).
b) Why is copy by value not possible for objects?
Wrong assumption in a) leads to this. Assignment is no copy and a copy of an object does not preserve equality.
Or think about:
var obj = {a: {b: 1}}
.
What is the value of obj.a ? It is just the reference to {b:1}.
c) What techniques are helpful for a beginner used to copying objects
by value to code without it?
There are many approaches for this. And two trivial cases.
As the first case one knows the layout of the object. Thus creates a template or constructor and passes all values into the corresponding properties.
As the second case one assumes a cyclic object containing everything possible in javascript (functions, regexp, symbols, undefined, ...) of depth n and builds something (not json.stringify).
For starters: possible duplicate
Assumptions:
primitive and non primitive data types have default getter,setter, ...
I guess it's because of the specific nature of JS. When you create an object like this:
let obj = {a: 3, b: 5}
And try to pass this object to another variable like this:
let obj2 = obj
You will still have only 1 object, but with 2 references, so if you try to modify obj.a it will also affect obj2.a.
That's why I created a way around for myself, which may not be the best, but here is it:
//A little helper
Object.isObject = function (object) {
return object !== null && object instanceof Object && !Array.isArray(object)
}
/*
* Array and Object copy work with each other, so every nested array are
* copied properly
*/
/*
* ARRAY
*/
Object.defineProperty(Array.prototype, 'copy', {
value: function (array){
if(!(Array.isArray(array))) throw new TypeError('passed value should be an instance of array')
if(array.length <= 0) {
console.warn('WARNING: Found nothing to copy')
return this
}
this.splice(0, this.length)
for(let i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) this[i] = Array().copy(array[i])
else if (Object.isObject(array[i])) this[i] = Object().copy(array[i])
else this[i] = array[i]
}
return this
},
enumerable: false
})
/*
* OBJECT
*/
Object.defineProperty(Object.prototype, 'copy', {
value: function (object){
if(!object || !(Object.isObject(object))) return false
if(Object.entries(object) <= 0) {
console.warn('WARNING: Found nothing to copy')
return this
}
const props = Object.getOwnPropertyNames(this)
for (let i = 0; i < props.length; i++) delete this[props[i]]
const keys = Object.keys(object)
const values = Object.values(object)
for (let i = 0; i < keys.length; i++) {
if(Array.isArray(values[i])) this[keys[i]] = Array().copy(values[i])
else if(Object.isObject([values[i]])) this[keys[i]] = Object().copy(values[i])
else this[keys[i]] = values[i]
}
return this
},
enumerable: false
})
//create 2 arrays
let a = [3, 5, {a: 5}, [3, 1]]
let b = []
//copy array of a
b.copy(a)
//modify values
b[0] = 6
b[2].a = 1
b[3][0] = 'test'
console.log(a) //source
console.log(b)
As you can see in the example these 2 arrays (a and b) are completely different and have no relation to each other.
P.S. Sorry if I wrote something wrong, my english is not that good :O
I am looking for a way to check if two variables refer to the same object in javascript.
ex:
var a = {foo:"bar"};
var b = {foo:"bar"};
var aa = a;
testSame(a, b); //false
testSame(a, aa); //true
var r = "a string";
var s = "a string";
var rr = r;
testSame(r, s); //false
testSame(r, rr); //true
So far there doesn't seem to be a way of getting a way of doing this.
edit: testSame() is not a real function it would be the hypothetical solution.
edit: The answer to the question How to check if two vars have the same reference? does not answer this question as it uses the strict equality operator (===) which does not differentiate between between 2 vars pointing to 2 instances of an identical string.
Just comparing with == or === will do the trick, except for strings. There's no way to do what you ask with strings.
var a = {foo:"bar"};
var b = {foo:"bar"};
var aa = a;
testSame(a, b); //false
testSame(a, aa); //true
var r = "a string";
var s = "a string";
var rr = r;
testSame(r, s); // false <-- this will be true
testSame(r, rr); //true
function testSame(a, b) {
console.log(a === b);
}
The question is correct, but there is a trick in it. The following console code snippet reveals it:
const A = "abc", B = new String(A), C = B
> A == B
true
> A === B
false
> B === C
true
Variable A refers integral primitive that is converted to String object on a demand. JS machine may optimize references to equal primitive strings defined in the code to target exactly the same block of RAM — that's why the question, as defined, has no solution.
You need to manually wrap each integral value to corresponding object class: String, Number, Boolean, — and test them with === operator:
var r = new String("a string");
var s = new String("a string");
var rr = r;
I've applied this trick to track the initially empty controlled input in React, — whether the user had edited it and then erased to be clear, — without involving additional field in the state.
Here's how things work. First, in this code:
var a = {foo:"bar"};
var b = {foo:"bar"};
the variables a and b are initialized with references to two different objects. Thus comparisons with either == or === will report them as being different (i.e., not equal).
Here, however:
var a = "some string";
var b = "some string";
the two variables are initialized to refer to strings that are identical. String values in JavaScript are not objects — they're primitives. Comparisons between a and b with either == or === will therefore return true because the strings are the same. This is exactly the same as things would have been if the variables had been initialized like this:
var a = 17;
var b = 17;
Numbers and strings are primitives, so comparison compares the semantic values of the primitives. Objects, however, are not primitives, and comparison of objects is based on object identity.
It literally is nonsensical in the JavaScript semantic domain to want to know whether two variables pointing to the same identical string refer to two different expressions of that same string, in precisely the same way as it would be nonsensical to want to know whether one 17 were different from another.
This one is already answered in this question:
How to check if two vars have the same reference?
The short version use === instead of ==
As I understand it, === checks the identity of the object. Javascript's strings are immutable, so when you say
var x = "string"
vay y = "string"
x and y are actually referencing the same object in memory. So, unfortunately, what you want is impossible. Symbols provide this functionality:
Symbol('x') === Symbol('x') // => false
This question already has answers here:
How to compare arrays in JavaScript?
(55 answers)
Closed 7 years ago.
I did the following. Very confused whether they are not equal.
var arr1 = []
arr1.push(1)
arr1.push(2)
arr1.push(3)
var arr2 = [1, 2, 3]
var isSame = (arr1==arr2)
Why is isSame false? Very confused about this...
As a rule of thumb, avoid using == since it is subject to complex coercion rules. === is simpler, more efficient and less bug-prone in general. The === operator in JavaScript, for arrays and objects, compares by reference - it only returns true if two variables reference the same object.
var a = [1,2,3];
var b = [1,2,3];
var c = a;
console.log(a === b); // false
console.log(a === a); // true
console.log(a === c); // true
For numbers, bools and strings, the === operator compares by value.
var a = "hi";
var b = "hey";
var c = "hi";
console.log(a === b); // false
console.log(a === c); // true
If you want to compare two numeric arrays by value, the best way of doing it is creating a function particularly for that:
function arrayEquals(a,b){
for (var i=0, l=a.length; i<l; ++i)
if (a[i] !== b[i])
return false;
return true;
}
This will only work if your array only contains native values - strings, numbers and booleans. If you want to compare a deeper structure, a quick and dirty way is serializing it to JSON and comparing:
var a = [[1,2],3,4];
var b = [[1,2],3,4];
var c = [[1,5],3,4];
console.log(JSON.stringify(a) === JSON.stringify(b)); // true
console.log(JSON.stringify(a) === JSON.stringify(c)); // false
This will work for any structure that is a valid JSON and is actually acceptably fast for usual operations, as JSON.stringify is usually implemented natively. So, tl;dr: just use JSON.stringify on your arrays before comparing.
when comparing variables you will only compare the variables itself and not their content.
strings, numbers aswell as booleans are simple types. they are always representing their value.
objects are different. if you compare objects, you will just check if an objects reference is equal to the objects reference of the second comparator.
by comparing objects you will never ever compare the variables they contain.
objects are simply containers for even more variables.
variables can be simple types aswell as objects.
you are simply comparing two foundations to figure out if they are exactly the same.
if you really want to compare the content of an array to the content of another array you need to recursively check every variable it contains aswell.
an example..
var obj = {};
obj.foo = "bar";
(function (o) {
o.foo = "baz";
})(obj);
console.log(o.foo); // will print "baz"
when doing it with arrays you will get the same result.
you might want to check out this question: Deep comparison of objects/arrays aswell as all of the duplicates
I was pondering something earlier. I wanted to check if a function had already been put into an array. If so throw an exception. I did this little test with the console...
So I guess I could say that the objects are always just references, and after setting a as x I could change x and a would be effected as well?
Would this mean that the condition x = a no matter what, which is what I want.
Using this to check if the function/object is already in the array I could just do this correct...
Is there a better way to do this?
Would this also mean that if I pass a variable to a function and mutate it in that function it will be mutated outside of that function as well?
EDIT
I guess I am right about the mutation with this little test. But I don't get why its bar in the first log in the second example
EDIT END
Example 1:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
console.log(x == a); //comes out false
//Set a as x
a = x;
console.log(x == a); //comes out true
Example 2:
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) != -1;
};
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
var z = a;
console.log(x == a); //comes out false
var l = [];
l.push(x);
//Set a as x
a = x;
l.push(a);
console.log(x == a); //comes out true
console.log(l.Contains(x)); //Should come out true
console.log(l.Contains(a)); //Should come out true
console.log(l.Contains(z)); //Should come out false
Your question isn't entirely clear to me but I'll try to answer as best I can.
Improving the function
Your function could be simplified to leverage the indexOf function.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) >= 0;
};
Also I want to point out that in your implementation you're looping through everything when you could exit early by returning inside the if.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
var i;
for (i = 0; i < this.length; i += 1) {
if (this[i] === obj) {
return true;
}
}
return false;
};
x == a
I think you understand but just want to clarify, x and a are different originally because they are referencing different functions. When you set x = a they are both pointing at the function declared originally in x and are therefore the same. Even thought the functions are identical in terms of implementation, they were both constructed and then placed in different parts of memory.
When you do this:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")}
x and a point to different functions. Even if you compare them for equality, they are not equal as all equality checking does here is see if they point to the same function or not - there is no attempt made to see if they would produce the same output when run or not (that is almost impossible to do in general, after all).
When you do something like x = a, x now references whatever a is referencing - the same object. So now they compare equal.
If you need to see if a function already exists in an array, I suggest instead of just placing arrays in a big list, you create a dictionary (hashmap, hashtable, whatever you want to call it) that uses strings as keys as function as values. The key would be the 'name' of a function - whenever you make that function you'd use the same name, and names in different places in memory but with the same characters in them WILL compare equal.
You're really confused. Everything in JavaScript (except for primitive data types, null and undefined) is an object, and objects are stored in variables as reference. Read the following answer to know more about the differences between the two: https://stackoverflow.com/a/13268731/783743
When you define two identical functions (in your case x and a) JavaScript sees them as separate functions. This is because in addition to the function body a function also maintains its own environment and state. Hence x and a are not the same function which is why x === a returns false.
By setting x = a you're essentially copying the reference stored in a into x. Hence they now point to the same function (which is the function a was originally referring to). The function x was originally referring to is now lost and will eventually be garbage collected. Thus x === a now returns true.
BTW you don't need to create a special Contains function to check whether an object is already inside an array. Just use indexOf:
var array = [];
function x() {}
array.indexOf(x); // returns -1
array.push(x);
array.indexOf(x); // returns 0
If the index is less than 0 the object is not in the array.
If you want to check whether the function body of two functions is the same then use this function:
function sameFunctionBody(a, b) {
return String(a) === String(b);
}
Now console.log(sameFunctionBody(x, a)) will return true as long as both the functions are exactly the same (including whitespace, parameters, function name, etc).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JavaScript compare arrays
var x = [""]
if (x === [""]) { alert("True!") }
else { alert("False!") }
For some reason, this alerts False. I cannot seem to figure out why. What can I do to make this alert True?
Two objects are equal if they refer to the exact same Object. In your example x is one Object and [""] is another. You cant compare Objects this way. This link maybe useful.
Compare values not whole arrays
...as they're objects and you're working with implicit references here. One object is stored in your x valiable which you're trying to compare (by reference) with an in-place created object (array with an empty string element). These are two objects each having it's own reference hence not equal.
I've changed your example to do what you're after while also providing the possibility to have an arbitrary number of empty strings in an array:
if (x.length && x.join && x.join("") === "")
{
alert("True!")
}
else
{
alert("False!")
}
This will return True! for any arrays like:
var x = [];
var x = [""];
var x = [null];
var x = [undefined];
var x = ["", null, undefined];
...
Arrays cannot be reliably compared this way unless they reference the same object. Do this instead:
if ( x[0] == "" )
or if you want it to be an array:
if ( x.length && x[0] == "" )
You could use toString in this case. Careful, there are some outliers where this will not work.
var x = [""]
alert(x.toString() == [""].toString()) // true
In JavaScript, two objects are equal only if they refer to the same object. Even [] == [] is false.
A probably slow but generic solution would be to compare the string representations of the two objects:
JSON.stringify(a1) == JSON.stringify(a2)