JavaScript if fails with [""] (an array containing an empty string) [duplicate] - javascript

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)

Related

Javascript: testing for at least one non-empty array (if one of the arrays may be null)

Given two arrays myArray1 and myArray2, which may be null, how can I output a Boolean which tells me if at least one array is non-empty?
Assuming that I have the following variables:
myArray1 = ["one", "two", "three"]; //-> non-empty array
myArray2 = null; //-> not an array (in my case this happens from .match() returning no results)
I want an expression, such that myArray1 && myArray2 will be FALSE, but myArray1 || myArray2 will be TRUE.
I did look through other relevant Stack Overflow questions (see an abridged list below), but since I still struggled to figure out the solution, I thought I would post it as a separate question since answers might also benefit others.
The common way of testing for empty arrays is:
myBooleanOr = (myArray1.length || myArray2.length); //3
myBooleanAnd = (myArray1.length && myArray2.length); //Error
This works if both variables are arrays, but in this case, the second one will throw up Error: cannot read property length of 'null'. Using the Boolean() function does not solve the problem since the following also throws up the same error:
myBooleanAnd = (Boolean(myArray1.length) && Boolean(myArray2.length)); //error
A solution for testing empty arrays which was accepted in several Stack Overflow questions is to use typeof myArray !== "undefined", but that still does not solve the problem, because neither of the arrays match "undefined", so myBooleanAnd will still throw up an error:
var bool = (typeof myArray1 !== "undefined"); //true
var bool = (typeof myArray2 !== "undefined"); //true
var myBooleanAnd = ((typeof myArray1 !== "undefined" && myArray1.length) || (typeof myArray2 !== "undefined" && myArray2.length)); //Error: cannot read property length of null
Comparing the arrays against [], which also seems intuitive, also doesn't work, because neither of the arrays match []:
var bool = (myArray1 !== []); //true
var bool = (myArray2 !== []); //true
Other relevant posts
A number of other questions on Stack Overflow deal with testing for empty Javascript arrays, including:
Testing for empty arrays: Check if array is empty or exists
Testing for empty arrays (jQuery): Check if array is empty or null
Relative advantages of methods for testing empty arrays: Testing for an empty array
Testing for empty objects: How do I test for an empty JavaScript object?
And there are also questions about the truth value of empty arrays in Javascript:
JavaScript: empty array, [ ] evaluates to true in conditional structures. Why is this?
UPDATE
I have corrected the following errors posted in the original question (thanks to those who pointed them out). I am listing them here since they might also be helpful to others:
==! changed to !==
typeof x === undefined, changed to typeof x === "undefined"
I would suggest using a helper function to determine if a single array is non-empty, and then use that twice. This is simple and straightforward:
function isNonEmptyArray(arr) {
return !!(Array.isArray(arr) && arr.length);
}
var myBooleanAnd = isNonEmptyArray(myArray1) && isNonEmptyArray(myArray2);
var myBooleanOr = isNonEmptyArray(myArray1) || isNonEmptyArray(myArray2);
Ok, so, there're a bunch of errors in the code examples, i'll try to to explain them all:
myBooleanOr = (myArray1.length || myArray2.length); //3
myBooleanAnd = (myArray1.length && myArray2.length); //Error
Here, the first line returns the first truthy value it encounters. Since myArray1 has a length > 0, it returns that value and never evaluates the second part of the condition, that's why you're not getting the error. Swap the checks and it will break.
The second line combines the two values to give a result, so it will always give an error when one of the two variables are null.
var bool = (typeof myArray1 === undefined); //false
typeof returns a string, if you compare it to the undefined constant it will always be false, the correct statement is typeof myArray1 === "undefined" as written in most of the posts you linked
var bool = (myArray2 ==! null);
the "strictly not equal" operator is !== and NOT ==!. You're doing a different operation and that's why you get surprising results.
Putting the right spaces in the syntax, this is your code var bool = (myArray2 == !null);
So you boolean-flip the value of null, which is falsy by nature, getting true, and then compare if myArray2 is loosely-equal to true ... since myArray2 is null, and that is falsy as we said, the comparison gives back a false.
That said, for the solution to the question, I'd propose a slightly longer syntax that is more explicit, clear to understand, and you can scale to check how many arrays you like without adding more complexity:
var myArray1 = [1,2,3]
var myArray2 = null
var arrays = [myArray1, myArray2]
var oneNotEmpty = arrays.some( a => typeof a != "undefined" && a != null && a.length > 0)
console.log("At least one array non-empty?", oneNotEmpty)
You could use isArray to check something is an array or not. Most modern browsers supports it. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
And then you can combine isArray and array's length to check if something is a valid non empty array or not.
function isOneNotEmpty(arrayOne, arrayTwo){
return (Array.isArray(arrayOne)? arrayOne.length > 0 : false) || (Array.isArray(arrayTwo)? arrayOne.length > 0 : false)
}
console.log(isOneNotEmpty([],null));
console.log(isOneNotEmpty([1,2,3,4],null));
console.log(isOneNotEmpty([3,4,5],[1]));
Testing for an array is simple enough:
var blnIsPopulatedArray = (myArray != null
&& typeof myArray == "object"
&& typeof myArray.length == "number"
&& myArray.length > 0);
Will return false if 'myArray' isn't an array with at least one item, or true if it is an array with at least one item.
One solution is the following (with or without Boolean()):
Using Array.isArray() and array.length:
var myBooleanAnd = Boolean(Array.isArray(myArray2) && myArray2.length) && Boolean(Array.isArray(myArray1) && myArray1.length) ; //false -> OK
var myBooleanOr = Boolean(Array.isArray(myArray2) && myArray2.length) || Boolean(Array.isArray(myArray1) && myArray1.length) ; //true -> OK
It is also possible to use myArray1 !== null instead of Array.isArray(myArray1), but since the latter is a more specific test, the broader Array.isArray() method seems preferable.
UPDATE
I had previously suggested using the following:
var myBooleanAnd = Boolean(myArray1 && myArray2); //returns false -> OK
var myBooleanOr = Boolean(myArray1 || myArray2); //returns true -> OK
but since, as pointed out by #JLRishe, the following expression also returns TRUE, this is not a safe solution, since it will only work in situations where the arrays can never be empty.
var bool = Boolean([] && []); //returns true -> false positive
function arrayIsEmpty(array) {
if (!Array.isArray(array)) {
return false;
}
if (array.length == 0) {
return true;
}
}

Why javascript pushed array and defined array not equal [duplicate]

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

obj == JSON.parse(JSON.stringify(obj)) is false [duplicate]

This question already has answers here:
How to determine equality for two JavaScript objects?
(82 answers)
Closed 8 years ago.
I was looking at the JavaScript console in Chrome and noticed something strange, even though they appear the same, obj and JSON.parse(JSON.stringify(obj)) are not the same. Why is that?
var obj = {test:'this is a test', another: {omg:'ay dios mio', check:true}};
console.log(obj, JSON.parse(JSON.stringify(obj)));
console.log(obj == JSON.parse(JSON.stringify(obj)));
They look identical but return false when you check equality. Why is that?
They're not equal for the same reason this returns false:
({omg:'ay dios mio', check:true}) == ({omg:'ay dios mio', check:true})
You're not comparing the values inside the object, but the object references. They'll be different.
The objects are testing for REFERENCES.
While primitives are testing for VALUE.
Because the obj does not reference the parsed object in memory. So these are 2 different declarations. If you do this:
var a = [ 10 ],
b = [ 10 ];
Then there are 2 instances of arrays with the same values, but that doesn't make them the same array. So a != b, even though 10 == 10. You can increase the value of a[0] to 15, but that doesn't change the value of b[0] to 15.
Therefore, if you want to compare objects, you have to loop through them and check if the values of the objects are the same.
A function to compare (borrowed from jQuery object equality )
$.fn.equals = function(compareTo) {
if (!compareTo || this.length != compareTo.length) {
return false;
}
for (var i = 0; i < this.length; ++i) {
if (this[i] !== compareTo[i]) {
return false;
}
}
return true;
};

How to find if value of an array is not defined?

If we have an array that does not exists and we check the value of the array it gives me an error. "variable is not defined"
for example I have:
var arr = new Array();
arr['house']['rooms'] = 2;
and I use
if ( typeof arr['plane']['room'] != 'undefined' ) )
it says arr['plane'] not defined...
I don't want to use this:
if ( typeof arr['plane'] != 'undefined' ) ) {
if ( typeof arr['plane']['room'] != 'undefined' ) {
}
}
In php I use isset that works nice for me, I searched a lot on google to find the answer but I can't...
The thing to realize is that there are no multi-dimensional arrays in javascript. It is easy to make an array element contain an array, and work with that, but then all references you make have to use that consideration.
So, you can do
arr = []; // or more appropriately {}, but I'll get to that soon
arr['house'] = [];
arr['house']['rooms'] = 2;
But doing
arr['house']['rooms'] = 2;
should give you an error unless you've already defined arr and arr['house'].
If you've defined arr but not arr['house'], it's valid syntax to reference arr['house'] - but the return value will (appropriately) be undefined.
And this is where you're at when you're looking at arr['plane']['room']. arr is defined, so that's ok, but arr['plane'] returns undefined, and referencing undefined.['room'] throws an error.
If you want to avoid the errors and have multiple levels of reference, you're going to have to make sure that all the levels but the lowest exist.
You're stuck with if (arr && arr['plane'] && arr['plane']['room']).
Or perhaps if (arr && arr['plane'] && room in arr['plane'] would be more accurate, depending on your needs. The first will check if arr['plane']['room'] has a truthy value, while the second will check if arr['plane']['room'] exists at all (and could have a falsey value).
Arrays vs objects
Arrays and objects are very similar and can both be accessed with [] notation, so it's slightly confusing, but technically, you're using the object aspect of the array for what you're doing. Remember, all arrays (and everything other than primitives - numbers, strings and booleans) are objects, so arrays can do everything objects can do, plus more. But arrays only work with numeric indices, i.e. arr[1][2]. When you reference an array with a string, you're attempting to access the member of the underlying object that matches that string.
But still in this case, it doesn't matter. There are no multi-dimensional arrays - or objects.
The [] notation with objects is simply a way to check for members of objects using a variable. arr['plane']['rooms'] is actually equivalent to arr.plane.rooms. but perhaps the arr.plane.room notation will help make it more clear why you have to first check arr.plane (and arr).
Use the following if you want to test for existence in an object:
if ( 'plane' in arr && 'room' in arr.plane ) {
// Do something
}
That's not an array, but an object, aka associative array. You can declare it like this:
var aarr = { house: { rooms: 2 } };
Now you can do:
if (aarr.house && aarr.house.rooms) {/* do stuff */ }
or uglier, but shorter:
if ((aarr.house || {}).rooms) {/* do stuff */ }
See also...
To more generally traverse an object to find a path in it you could use:
Object.tryPath = function(obj,path) {
path = path.split(/[.,]/);
while (path.length && obj) {
obj = obj[path.shift()];
}
return obj || null;
};
Object.tryPath(aarr,'house.rooms'); //=> 2
Object.tryPath(aarr,'house.cellar.cupboard.shelf3'); //=> null
JsFiddle

Is all JavaScript literal object different from each other

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.

Categories