I do not understand this Splice behaviour in google app script - javascript

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]

Related

Javascript confusing order of execution [duplicate]

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}`);

How to add data to an array without push because it returns the length?

Simple. I have this array and I am trying to add a value to it but when I use push it just returns the length of the array after I push the value. I remember finding a way around this with a different function but I cannot remember what it was.
I will give a bit of context:
function submitCommentHandler() {
firestore.collection("posts").doc(title).update({
comments: comments.concat(newComment)
})
navigate("/all-posts");
}
There is the function to add a comment, but when I run that function it changes the value of comments in the firestore db to a number instead of the full array. If the value of the comments changes to a number I cannot access the text within the comments.
I decided to just do comments.push(newComment) and then set the comments to comments in the object. I think thats what some people were telling me.
When you use push() to add a value to an array, the value is pushed to the original array.
const values = [1];
const pushValue = values.push(2);
console.log(pushValue); // 2
console.log(values); // [1, 2]

Add output to an array of each for loop

I'm trying to call a REST API using for loop and store the output to an array. But the output shows in different arrays for each and every rest API call instead of everything in one array
for each (name in car.cars){
for(i=0; i<count;i++){
var arr = [];
var newid = car.cars[i].name;
var url = "myhost"
var method = "GET"
var response = "output from REST call"
arr.push(response)
}
}
But the output shows in different arrays for each and every rest API call instead of everything in one array
Where is "the output" there's nothing in your code.
Your Problem is that you're declaring the var arr = []; inside your for loop.
Initialize the array before the loop starts and just add your responses to that array.
Instead your creating a new array for each iteration of for(i=0; i<count;i++)
Take a step back and look at your code again. Where are you declaring your array? Inside the loop.
Next, ask yourself; what is the scope of that array? Only within the loop. Even if just in the outer loop, it won't stick around because as soon as that loop finishes, the array disappears.
Create the array and use it from outside the loops (both of them).
Further reading: Declaring variables inside or outside of a loop
UPDATE 4/30/2019: Thanks to #AuxTaco, I crossed out my inaccurate description of scope in JS. Please see the links in his comment for more reading on this!

javascript array attributes passed by reference

in this example, it seems that we can use a variable (here "second") to fill the array myArray, as if second was a "reference" to myArray : is that really what happens here?
var myArray = [];
var second = myArray;
second.target = … //we fill the "second" variable
second.offsetX = …
second.offsetY = …
var target = myArray.target; //then we retrieve the result from myArray
if (target) {
Thanks
second was a "reference" to myArray : is that really what happens here?
Yes.
Objects—like arrays—in JavaScript are passed and assigned by reference.
From your example, myArray and second both point to the same object in memory.
Yes, this is exactly what happens here. When you (for example) push new elements to second, you can read them later from myArray.
BTW, I sense that you're doing something strange. Why do you set an offsetX on an array?
This is called a shallow copy. You have a reference (var second = ...) to the original array (var myArray = ...), they both are pointing to the same memory in the memory of the JavaScript virtual machine.
This way you can access the array either by second or myArray.
var myArray = [];
This is just an array declaration It is same as var myArray=new Array();
About Array Referencing:
var second = myArray;
We are pointing the variable second to myArray memory location. Here new Object second will be created point to content of myArray. So, if you read content of second. It will read the myArray. But, you edit/update the content of second, content of myArray will be copied into second and it will be modified. As Bakudan said, It is the shallow copy. See the example below,
var myArray=[10,20,30];
var second =myArray; //second will contain 23,45 and 100.
If we update the array second, second=[100,200,300]
Original contents will be cleaned and 100,200,300 will be written.
To append the content to array second without removing the original content, We need to use function push as below:
second.push(100);second.push(200),second.push(300);
Now, content of second will be 10,20,30,100,200,300.
Object Property:
second.target = "testString";
second.offsetX =87;
second.offsetY =56;
This is the creation of object properties. It is same as,
second={"target":"testString","offsetX":87,"offsetY":56};
If you want to access value 87, it can be accessed as second.offsetX or second[offsetX].
More Information about java script Array is available here.

should i use `delete array[x]; array.length-=1` instead of `array.splice(x,1)`?

I want to remove an item from an array, is array.splice(x,1) the best way to go?
Is array.splice(x,1) functionally equivalent to delete array[x]; array.length-=1 ?
I've read these threads: Javascript object with array, deleting does it actually remove the item? and Deleting array elements in JavaScript - delete vs splice
and did some tests:
<script>
var arr=[];
for(var x=0;x<100000;++x){
arr.push(x);
}
var a=new Date().getTime();
for(var x=0;x<50000;++x){
arr.splice(49999,1);
}
var b=new Date().getTime();
alert(b-a);
</script>
<script>
var arr=[];
for(var x=0;x<100000;++x){
arr.push(x);
}
var a=new Date().getTime();
for(var x=0;x<50000;++x){
delete arr[49999];
arr.length-=1;
}
var b=new Date().getTime();
alert(b-a);
</script>
The timing difference is over a magnitude of 100, making the itch to use the second solution almost irresistable.. but before using it, I would like to ask this question: are there any traps i should look out for when i use delete array[x]; array.length-=1 instead of array.splice(x,1)?
If you're just lopping off the last element in the array, you can use pop() and throw away the result or just decrement the length by 1. The delete operator isn't even required here, and splice() is more appropriate for other uses.
Specifically, section 15.4 of the ECMAScript specification says:
whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted.
Both methods mentioned are outlined at MDC:
Array pop()
Array length
Either are appropriate for your situation - by all means modify length if you get better performance from it.
array.splice may perform other internal operations relevant to the splice.
Your delete array[x]; array.length-=1 just hacks around the public interface and assumes that there's nothing else to do internally.
In fact, this is the cause of the timing difference: there is plenty more to do internally in order to actually splice the array.
Use the proper interface. That's why it's there.
Using delete does not delete the element. After delete somearr[n] somearr[n] still exists but its value is undefined. There are a few ways to remove elements from arrays.
within an array for one ore more elements: Array.splice
from the end of an array (i.e. the last element): Array.pop() or maybe Array.length = Array.length-1
from the beginning of an array (i.e. the first element): Array.shift() or Array.slice(1)
To be complete, using Array.slice you could make up a function too:
function deleteElementsFromArray(arr,pos,n){
return arr.slice(0,pos).concat(arr.slice(pos+n));
}
Deleting array elements just sets them to undefined - that's why it is so fast. It does not remove the element. Decreasing the length of the array makes it even worse as the array length doesn't change at all!
In other words: the response to your question title is no and you should use splice() to achieve the intended effect. You can use the delete 'trick' to achieve greater performance only if your code handles the possibility of undefined elements. That can be useful, but it has nothing to do with 'removing an item from an array'.

Categories