Javascript confusing order of execution [duplicate] - javascript

This question already has answers here:
Change the value of an array changes original array JavaScript
(3 answers)
Closed 5 months ago.
I was playing around with reverse() to see how it works and came across this interaction that I can't understand at all. Here is the initial code:
let muhArray = [1,2,3,4,5];
let reversedArray = muhArray.reverse();
console.log(`muhArray: ${muhArray}`);
console.log(`reversedArray: ${reversedArray}`);
This returns:
muhArray: 5,4,3,2,1 (Original array changed as well)
reversedArray: 5,4,3,2,1
I figured that since reverse() reverses arrays in-place, even if it is an initilization, it changes the original muhArray anyways. So I created a copy(muhArrayCopy) to preserve the original array.
let muhArray = [1,2,3,4,5];
let muhArrayCopy = muhArray;
console.log(`muhArrayCopy: ${muhArrayCopy}`);
let reversedArray = muhArray.reverse();
console.log(`reversedArray: ${reversedArray}`);
This returns:
muhArrayCopy: 1,2,3,4,5
reversedArray: 5,4,3,2,1
Up until this point everything seems fine, but changing the order made me realise muhArray.reverse() affects already declared and initialized muhArrayCopy as well.
let muhArray = [1,2,3,4,5];
let muhArrayCopy = muhArray;
let reversedArray = muhArray.reverse();
console.log(`muhArrayCopy: ${muhArrayCopy}`);
console.log(`reversedArray: ${reversedArray}`);
Such order returns:
muhArrayCopy: 5,4,3,2,1
reversedArray: 5,4,3,2,1
Is this maybe a code execution order thing? I have read about hoisting but that does not seem to explain it, as far as I can understand. I am all new to programming so I have little to no knowledge about it.
Thanks in advance.

js is call by reference, so
let muhArrayCopy = muhArray;
does not create a copy, it puts the reference of variable in the other one, so both are affected when something happens to the other.
let muhArray = [1,2,3,4,5];
let muhArrayCopy = [...muhArray];
let reversedArray = muhArray.reverse();
console.log(`muhArrayCopy: ${muhArrayCopy}`);
console.log(`reversedArray: ${reversedArray}`);
this should solve it. here [...muhArray] we are creating a copy of the array.

There is nothing unexpected happening here. In the first code snippet, you print the array copy before reversing the original array. Keep in mind that the "copy" still points to the original array. In the second snippet, you print the copy after reversing the original source.

[Array.prototype.reverse()][1] from definition The reverse() method reverses an array in place and returns the reference to the same array
So when you apply reverse to an array, it changes the parent array as well.
If you want to make your original array unchanged, you have to copy the original array to an another memory location and reverse it.
Assigning a variable to another will copy the memory location of the same variable. So what ever changes made to the existing variable will be reflected to the assigned variable as well
You should not copy the variable, instead you have to clone it and assign it to another variable. This can be done using Deep Copy and Shallow Copy
Read more about Deep Copy v/s Shallow Copy here
Since the variable here is an array, just clone it with Spread operator and reverse it.
Working Example
let muhArray = [1,2,3,4,5];
let muhArrayCopy = muhArray;
let reversedArray = [ ...muhArray ].reverse();
console.log(`muhArrayCopy: ${muhArrayCopy}`);
console.log(`reversedArray: ${reversedArray}`);

Related

I do not understand this Splice behaviour in google app script

I have made a function that randomizes the order of answers in a quiz builder.
I pass in an array, the elements contain a question, some answers, and some other info. The correct answer is always in index 2 and this position needs to be randomized before a quiz question is generated.
function randomiseAnswers(question)
{
//return an array with 5 elements, 0 to 4. Element 4 contains the index of the correct answer.
//INPUT PARAM = Topic; Question; Correct; Distractor; Erroneous; Erroneous; Resource
var correct = question[2];
var answers = [];
var temp = question;
temp.splice(2,4);
shuffleArray(answers);
answers.push(answers.indexOf(correct))//make sure final element is the position of the correct answer
//Logger.log(answers);
return answers;
}
When I use this function, the original array that is passed to the function is being modified even though I only use a splice on a copy of the array called 'temp' inside the function.
When I replace the splice method with some push()es instead the original array remains intact and the function works as intended.
Why would splice modifying the array 'question' when it is only being used on a temporary array?
Use let/const instead of var. Var is outdated
To solve your problem:
const temp = [...question]

Shifting the new variable also shifts the old original one

How come with this
var prodataTemp = [];
prodataTemp = prodata;
prodataTemp.shift();
both variable prodatTemp and prodata are shifted? I can see it in the console.
Assigning a JavaScript object to another variable, will not copy the contents, but it make the left hand side variable, a reference to the right hand side expression. So,
var prodataTemp = [];
made prodataTemp refer an empty array and then
prodataTemp = prodata;
makes prodataTemp refer the same array object prodata was pointing to. (So, the old empty array is no more referenced by prodataTemp).
To actually make a copy**, use Array.prototype.slice, like this
prodataTemp = prodata.slice();
Now, prodataTemp refers to the copy of the array prodata, so that shifting one will not affect the other.
** - The copy made is just a shallow copy. So, if you have an array of arrays, then a new array will be created with all the references to the elements of the old array. So, mutating one array element will have its impact in the other as well.

How do I save a copy of an array before sorting? [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 9 years ago.
I'm trying to save a copy of the array before I sort it:
words_Array = ["Why", "doesnt", "this", "work?"];
var sortedWords_Array = words_Array;
sortedWords_Array.sort(function(a, b){
return b.length - a.length;
});
alert("sortedWords_Array is :"+sortedWords_Array);
alert("words_Array is :"+words_Array);
After I sort sortedWords_Array, they're both sorted for some reason. http://jsfiddle.net/zv39J/ Why is that?
Because in javascript, arrays are passed by reference which means that when you make one array equal to another it will change both whenever you make an edit to one. To fix this in your example change the following line:
var sortedWords_Array = words_Array;
to:
//make a copy of array by using slice
var sortedWords_Array = words_Array.slice(0);
See here for other uses and a more in-depth explanation:
slice does not alter the original array, but returns a new "one level
deep" copy that contains copies of the elements sliced from the
original array.
Array.prototype.slice()
Do a slice() on the array to duplicate, and then sort.
var sortedWords_Array = words_Array.slice();
Use the slice function to make a fast copy.
http://jsfiddle.net/zv39J/2/
On another note—alerts are terrible. No one wants to click a jsfiddle only to be greeted by a series of alert windows. I've updated the fiddle to include jQuery, which allows us to use a nice succinct syntax to make updates to the HTML.
This wont work because when you try to assign
var sortedWords_Array = words_Array;
The reference of words_array is passed to sortedWords_Array. So any change made to sortedWords_Array will be reflected on words_array.
Since Array.slice() does not do deep copying, it is not suitable for multidimensional arrays:
var a =[[1], [2], [3]];
var b = a.slice();
b.shift().shift();
// a is now [[], [2], [3]]
Note that although I've used shift().shift() above, the point is just that b[0][0] contains a pointer to a[0][0] rather than a value.
Likewise delete(b[0][0]) also causes a[0][0] to be deleted and b[0][0]=99 also changes the value of a[0][0] to 99.
jQuery's extend method does perform a deep copy when a true value is passed as the initial argument:
var a =[[1], [2], [3]];
var b = $.extend(true, [], a);
b.shift().shift();
// a is still [[1], [2], [3]]

Passing a JS Array to a new Array [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 8 years ago.
sorry very basic question I'm new.
If I have an array and pass it to a new variable (newArray = oldArray) then remove an element from newArray, it seems to also effect oldArray.
my guess is that it's simply creating a new reference to the same variable, so that data that was stored in oldArray now has two identifiers?
If so how do I actually pass the elements from oldArray into newArray so that newArray is independent from oldArray?
Thanks in advance
my guess is that it's simply creating a new reference to the same variable, so that data that was stored in oldArray now has two identifiers?
Right, both your new variable and your old one are pointing to the same array. Operations on the array through one reference (variable) are naturally visible through the other one, since there is just one array.
To avoid this, you'd have to make a copy of the array. There are several ways to do that, one of which is to use slice:
var newArray = oldArray.slice(0);
slice returns a shallow copy of an array starting at the given index. If you give it the index 0, it copies the entire array.
The quickest way is to use an array function to return a new array instance. Typically, I use:
var newArray = oldArray.slice(0);
In that case you have to clone the array using the slice method:
newArray = oldArray.slice(0);
As you've learned, when you copy an array variable, you copy a reference to the original.
Here's one idom to make a real copy - request a slice from the first element
var newArray = oldArray.slice(0);

Javascript array index

Sorry for asking a noob question but if I have an array:
MyArray["2cd"]="blah1";
MyArray["3cx"]="blah3";
MyArray["8cz"]="blah2";
And a string myStr="2cd";
And then I use MyArray[myStr] to get the value of blah, how can I get the number I am accessing in the object/array or 0 in this case?
If I may read between the lines, it sounds like you're thinking that the code you posted:
MyArray["2cd"] = "blah1";
MyArray["3cx"] = "blah3";
MyArray["8cz"] = "blah2";
will automatically become the equivalent of:
MyArray[0] = MyArray["2cd"] = "blah1";
MyArray[1] = MyArray["3cx"] = "blah3";
MyArray[2] = MyArray["8cz"] = "blah2";
and therefore you can get the string "blah1" either of these two ways:
var foo = MyArray[0]; // sets foo to "blah1"
var bar = MyArray["2cd"] // also sets bar to "blah1"
But that's not how JavaScript works.
You certainly can set things up so you can use my MyArray[0] and MyArray["2cd"] to fetch the same value, but you have to do it explicitly as in my example.
One thing you didn't mention is how you declared MyArray itself. Is it an Array or an Object? That is, before the code you posted, did you create MyArray with:
var MyArray = {}; // or equivalently, var Array = new Object;
or:
var MyArray = []; // or equivalently, var Array = new Array;
The first example creates an Object, the second an Array.
What is a bit confusing is that JavaScript has both of these two types, which in many cases you can use somewhat interchangeably. But it's customary to use an Object when you are using arbitrary (generally but not necessarily non-numeric) keys into the object, as in your example. Conversely, it's customary to use an Array when you are primarily using strictly numeric indexes.
In fact, JavaScript's Array type inherits from the Object type. An Array is simply an Object with some additional behavior:
An Array has additional methods such as .push() which appends an item to the array.
An Array has a .length property which is automatically updated when you add elements with .push() or a direct array[123] assignment, or when you remove elements with .pop() or other methods.
What JavaScript doesn't have, as Fabrício pointed out, is an "associative array" that behaves like what you might find in some other languages. It has Objects and it has Arrays (which inherit from Objects), and you have to deal with each of those on their own terms.

Categories