Are elements of Javascript arrays processed in a defined order? - javascript

For example:
var a = [];
function p(x) { a.push(x); }
[[p(1),p(2)],p(3),[p(4),[p(5)]],p(6)]
a == [1,2,3,4,5,6] // Always true?
Is 'a == [1,2,3,4,5,6]' defined behavior? Can it be relied upon?

Are elements of Javascript arrays processed in a defined order?
Yes they are.
Is 'a == [1,2,3,4,5,6]' defined behavior? Can it be relied upon?
No, the equals operator performs referential equality when comparing object.

Short answer: "Yes".
Longer answer: Your question is actually about JavaScript statements in general and not Arrays. The code you posted ([[p(1),p(2)],p(3),[p(4),[p(5)]],p(6)]) is not an Array, it is a statement that returns an Array whilst also populating an Array. JavaScript statements are executed according to the rules of operator precedence.

Your question is not very clear, what do you mean by "processed"?
var a = [];
That is an array literal, it assigns a reference to an empty array to a.
function p(x) { a.push(x); }
Each time push() is called, a new element is added to a at index a.length (i.e. it is always added after the highest index).
[[p(1),p(2)],p(3),[p(4),[p(5)]],p(6)]
That is an array literal that is equivalent to:
a = [];
a[0] = [p(1),p(2)];
a[1] = p(3);
a[2] = [p(4),[p(5)]];
a[3] = p(6);
The following expression:
a == [1,2,3,4,5,6]
is always false, since arrays are objects and objects are never equal to any other object. You can do:
var a = [0, 1];
var b = a;
a == b; // true since a and b reference the same array
But
var a = [0, 1];
var b = [0, 1];
a == b; // false since a and b reference different arrays

Related

Set.prototype.has() returns false

I am learning ES6 Sets. I am trying to add an array and check its existence in the set but it is returning me false. Here is the code I am working on.
const set = new Set();
set.add(1);
set.add([2, 3]);
set.add([2, 3]);
console.log(set);
console.log(set.has([2, 3]));
Please can someone explain this behaviour.
When a Set contains an object, .has() determines whether or not the Set contains the same exact object, not whether the Set contains an object that contains the same data as some other object. It has to contain the same object.
So, .has(someObj) or .has(someArray) only returns true if that actual object is in the Set. It does not compare to see if a similar object with the same values/properties are in the Set, only if the actual object itself is in the Set.
It works similar to comparing two objects with === as in obj1 === obj2.
If you wanted something with features similar to a Set that would tell you if it had any other object matching the current one, then you'd have to write a different collection yourself and implement your own comparison algorithm. This is not how a Set or a Map work.
You can see some other discussion of a similar topic here: How to customize object equality for JavaScript Set
This should work:
const set = new Set();
const array = [ 2, 3 ];
set.add(1);
set.add(array);
set.add(array);
console.log(set);
console.log(set.has(array));
Set#has checks for object identity, not deep equality. This is different than, say, Java's HashMap, which uses Object#equals in the background.
just because primitive value is immutable
and object is reference (such as array, function etc) and reference object is mutable
see example
let x = 1; // orginal
let y = x; // copy
y = y + x; // modifing
console.log(x); // return 1
console.log(y); // return 2
Note: example above is not impacting in original value
// reference object
let x = [1]; // orginal
let y = x; // copy
y.push(2);
console.log(x); // return [1, 2]
console.log(y); // return [1, 2]
note: example above is impact in all
// comparison
let a = [1];
let b = [2];
console.log(a === b); // return false
console.log(a !== b);
Note: example above to know reason go to this link - https://dmitripavlutin.com/value-vs-reference-javascript/#:~:text=The%20simple%20rule%20of%20passing,Every%20single%20time.

Difference between two variable one is assigned a value undefined and second one is only declared a var not initialized

What is different between two variable one is assigned a value undefined and second one is only declared a var not initiased ?
var a = undefined;
var b;
a === b; // returns true
What is different between two variable a and b?
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
ar.filter(function(item, index, arr){
return item == undefined;
}); // [null, undefined]
I know Array's filter function runs for only initialized index.
How javascript internally check that ar[1] is assigend undefined so run filter for this and ar[2] is unassigned undefined so dont run for this ?
There are three separate issues going on here:
A regular variable that has just been declared, but not assigned a value will report undefined when you read that variable. That is essentially its default value.
You have to be very careful when comparing null with == because you will find that null == undefined is true because of auto-type conversion. So, if you want to filter on only undefined elements, you have to use item === undefined in the filter.
.filter() only iterates elements in the array that have actually been assigned a value. Unlike plain variables, there is a difference between an array element that has assigned a value and one that has never been assigned a value and .filter() knows to skip the ones that have never been assigned a value (the ones that are essentially "sparse").
Here's some more detail on these three issues:
A variable that has been declared, but not explicitly initialized, has a value of undefined. That is its default value.
This, this code is as expected:
var a = undefined;
var b;
a === b; // returns true
Then, in your second code block, if you want to truly test for whether something is undefined, then you need to use ===, not == to avoid any type conversion.
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
var result = ar.filter(function(item, index, arr){
return item === undefined;
});
for (var i = 0; i < result.length; i++) {
document.write(i, ": ", result[i], "<br>");
}
Note: .filter() will skip elements of the array that have not been initialized to have any value, thus they will never even be considered in the .filter() operation. If you try to read their values, you will get undefined, but .filter() knows the difference between a "sparse" array value that has never been assigned anything. It has to do with whether the array key exists or not, not what the value is and thus it is different for array items than it is for plain variables.
From the MDN doc for .filter():
The range of elements processed by filter() is set before the first
invocation of callback. Elements which are appended to the array after
the call to filter() begins will not be visited by callback. If
existing elements of the array are changed, or deleted, their value as
passed to callback will be the value at the time filter() visits them;
elements that are deleted are not visited.
Here's a demonstration of how the array keys do not actually exist until someting is assigned to the array element. This is the information that .filter() uses to know what to iterate and what to skip:
var ar = new Array(4);
ar[1] = "foo";
ar[2] = undefined;
for (var index in ar) {
document.write(index, ": ", ar[index], "<br>"); // 1 foo, 2 undefined
}
Note that indexes 0 and 3 are not iterated with the for loop because those keys do not exist in the array. The array is "sparse". Only some elements actually exist.

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

Why is JavaScript passing by reference? [duplicate]

This question already has answers here:
Why isn't this object being passed by reference when assigning something else to it?
(4 answers)
Closed 9 years ago.
var a = [3, 4, 5];
var b = [6, 7, 8];
function why() {
b = a;
b[0] = 1;
alert(a[0] + ' ' + b[0]);
}
why();
The result is a[0]=1, b[0]=1;. It seem likes JavaScript is passing by reference?
But in this case:
var a = [3, 4, 5];
var b = [6, 7, 8];
function why() {
b = a;
b = [1, 2, 3];
alert(a + ' ' + b);
}
why();
The result is a=[3,4,5] and b = [1,2,3]. Why is it passing by value?
How to avoid passing by reference?
The value of a non primitive variable, in JavaScript like in most object languages, is a reference to the object.
In the second case, you're not changing the array, but the reference that is stored in b.
If you want to copy your array, use
var c = a.slice();
Then c and a will evolve independently.
Because that's how variables work.
In the first case, you're setting both variables to the same instance of one array, then modifying that array through b (b[0] = 1). You could also modify the same array through a, but the point is b and a point to the same array; b does not "point" to a.
In the second, you're setting both to the same instance of one array (b = a) but then setting b to an instance of an entirely new, different array (b = [1,2,3]). You're changing the array that b points to, you're not affecting a because, as I said, b didn't point to a, it pointed to the same value as a.
The variables b and a are pointing to an object. When you do b = // something, you're changing where the variable points to. You're not changing the underlaying object.
In the first code, b = a means that b and a are now pointing to the same object. Therefore, when you make a change to one, it's reflected in the other.
However, in the second example, you're first pointing b to the same object as a, but then pointing b to a new array ([1,2,3]). The fact it was pointing to a for a short amount of time is irrelevant.
Both cases are pass-by-value. JavaScript is always pass-by-value, there is no way to pass by reference. In particular, the value being passed is always a pointer to an object. (Actually, primitives are passed by value directly, but the difference can only be observed for mutable values and primitives are immutable, so it doesn't make a difference.)
In the first case you are mutating the object the pointer points to. But the reference doesn't get changed, only the object the reference points to. The reference still points to the same object, the object just looks different than it did before.
This specific case of pass-by-value-where-the-value-is-a-pointer is sometimes called call-by-object-sharing, call-by-object or call-by-sharing, and is the way argument passing works in pretty much all object-oriented languages: Smalltalk, Python, Ruby, Java, C# (by default, you can pass-by-reference by explicitly specifying the ref modifier) etc.
In first case are changing one value of array item. b now equals to a so a[0] and b[0] gives same value.
In second case even though you made b point to a, you assigned a new object to b. so again b and a are two different objects ...so different values.
After all these great Answers, there is not really more to say, so heres an explanation based on the ECMAScript 5 specification.
Also a deepclone function at the end of the Answer.
As defined in the ES5 specification,
11.13.1 Simple Assignment ( = )
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
Let lref be the result of evaluating LeftHandSideExpression.
Let rref be the result of evaluating AssignmentExpression.
Let rval be GetValue(rref).
Throw a SyntaxError exception if the following conditions are all true:
Type(lref) is Reference is true
IsStrictReference(lref) is true
Type(GetBase(lref)) is Environment Record
GetReferencedName(lref) is either "eval" or "arguments"
Call PutValue(lref, rval).
Return rval.
So whats happening when we reach point 3 and rref is an Object, is
§8.7.1 (section 4b of In GetValue(V) //V==rref is the interesting point)
4.
If IsPropertyReference(V), then
(b) Return the result of calling the get internal method using base as its this value, and passing GetReferencedName(V) for the argument.
Now at this point rval holds the reference to the Object, which then gets put in at 5.
Where §8.7.2 (again 4b of PutValue(V,W) //V==lref , W==rval is the interesting part) comes into play.
Note: W is atm the reference to the Object you want to assign and not the value
4.
Else if IsPropertyReference(V), then
(b) Call the put internal method using base as its this value, and passing GetReferencedName(V) for the property name, W for the value, and IsStrictReference(V) for the Throw flag.
As you can see in your case the value of b which is atm a reference to the Object [6, 7, 8] gets replaced with the result of, so to speak GetValue(rref), which is a reference to [1, 2, 3];
However
Apparently you are looking for a deep clone function
Here is one.
Object.defineProperty(Object.prototype, "clone", {
value: function (deep) {
var type = Object.prototype.toString.call(this).match(/^\[object (.+?)\]$/)[1];
if (type !== "Object") {
return this.valueOf;
}
var clone = {};
if (!deep) {
for (var prp in this) {
clone[prp] = this[prp];
}
} else {
for (var prop in this) {
if (typeof this[prop] !== "undefined" && this[prop] !== null)
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone((typeof deep == "boolean" ? deep : (deep - 1))));
else
clone[prop] = "";
}
}
return clone;
},
enumerable: false
});
Object.defineProperty(Array.prototype, "clone", {
value: function (deep) {
var clone = [];
if (!deep) clone = this.concat();
else this.forEach(function (e) {
if (typeof e !== "undefined" && e !== null)
clone.push((typeof e !== "object" ? e : e.clone((deep - 1))));
else
clone.push("");
});
return clone;
},
enumerable: false
});
var a = [1, [2, { a: 3 } ], 4];
var b = a.clone(Infinity);
a[1][1]["a"] = "cloned";
console.log(a[1][1]["a"], b[1][1]["a"]); //"cloned" , 3
And a Demo on JSBin
To use it just call .clone(levelOfDeepness) on an Object or Array
Note: I used the Objects prototype for simplicities sake as i can call directly .clone of Object and Array elements while cloning them (gives a performance boost over the type checking variant in a single function)

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