javascript forEach array callback timing? - javascript

So im learning about the different array iterating methods and ran into something odd:
[1,2,3].forEach(function(element,index,arr){
console.log(element,index);
console.log(arr);
arr.shift();
})
So you would think this would produce:
1,0
[1,2,3]
2,1
[2,3]
3,2
[3]
however you get this:
1 0
[1, 2, 3]
3 1
[2, 3]
Im printing off 3 despite have only shifted off at the end? Is this because the arr callback happens at the beginning of the next item or something? Since it should be doing shift() on the array AFTER? I realize this is a "bad case" of using this method, im just curious why this happens.

The .length of the array is changed. The element adjacent to element at index 0 becomes index 0 following .shift() call.

The answer to your question is described in the documentation of shift method.
As per MDN from here
The shift method removes the element at the zeroeth index and shifts
the values at consecutive indexes down, then returns the removed
value. If the length property is 0, undefined is returned.
So, once the shift operation is done the Original array is changed from
[1,2,3] to [2,3] and the value of index increments from 0 to 1. Next, iteration the third iteration of the loop is Not required as the length of the array (2) has been traversed.

Related

problem while checking if an element exist in an array

i was traying to do the odin project exercises of javascript,
when I execute this line in the console
2 in [2,3,4,5]
it gives
true
but when I execute 3 in [3,4,5] in the console it gives back false I think it should also be true!!!
any explanation please
thank you in advance
The in operator checks if a property key exists on an object. You can think of this array as having 4 keys.
const arr = [2, 3, 4, 5];
// arr has the keys `0`, `1`, `2`, and `3`.
console.log(arr[0], arr[1], arr[2], arr[3]);
So when you have the expression 2 in arr, you are checking if the array has a key 2, not if the value 2 exists in the array.
If you do want to check if an array contains an item, the includes() method would achieve what you want.
const arr = [2, 3, 4, 5];
arr.includes(2); // true
arr.includes(0); // false
It behaves like this because the in operator returns true if the specified property (not value) is in the specified object.
So in the first case the array has a length of 4 with indices 0,1,2,3 so the element with the index 2 exists.
In the second case there are 3 elements with indices 0,1,2, so there is no element with an index 3 that is why it returns false.

How while(array.length) works without any increment/decrement [duplicate]

I understand that it's removing the first 3 elements of the array and adding them to the new array. But how does the function continue to add ensuing chunks of the array to the new array variable?
How does the while loop work without proper conditions?
How does it work in collaboration with splice() here?
function chunkArrayInGroups(arr, size){
let newArr = [];
while(arr.length){
newArr.push(arr.splice(0, size))
}
return newArr;
}
chunkArrayInGroups(["a", "b", "c", "d"], 2);
The condition is while(arr.length). The while loop will run while that condition is truthy. In JavaScript every condition is truthy unless it is one of the following:
false
0 (zero)
'' or "" (empty string)
null
undefined
NaN (e.g. the result of 1/0)
In your case the while loop will run while the array has elements in it (arr.length is greater than zero), because if the arr.length is zero the while loop will stop executing.
arr.splice on the other hand is removing one element from arr every time it is executed (it is changing the arr length). So when there are no elements left in the arr (because arr.splice removed them all) the while loop will stop.
Conditions in js are either "truthy" or "falsy", for numbers everything except 0 is "truthy", 0 is "falsy". That means that the loop runs until the array is empty, its length 0 and therefore falsy.
if(0) alert("never");
if(1) alert("always");
let i = 3;
while(i) console.log(i--);
The while loop is gonna keep going until the original array is empty. Splice will remove the selected elements from the original array and while will continue until the last elements are removed.
Also, as the elements are removed from the original array, they are being pushed (added) to the new array

Why doesn't array.splice() work when the array has only 1 element?

Is this intended behavior? I would expect an empty array to be returned here.
JavaScript
let arr = [1];
console.log(arr.splice(0, 1))
Console
1
Because it returns what was removed, which is [1] in your case. arr will be empty after the call.
See example:
let arr = [1];
arr.splice(0, 1);
console.log(arr);
Array.prototype.splice() returns an array of the deleted elements.
Your are logging the returned value of the operation not the current state of the array.
The splice() method changes the contents of an array by removing
existing elements and/or adding new elements.
Reference
The syntax of this method is:
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)
You are using the second syntax and passing 0 as start and 1 as deleteCount that means you would like to start at 0th index and delete 1 item (not 1 as value in array).
This method returns an array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned.
So, in this case the result is [1] i.e. an array with value of 1 that is the item you just deleted.
I ran into this question when I was trying to achieve a function in mini-program. A solution is to check the array's length before using the function splice. For example:
if(imgList.length > 1){
imgList.splice(index, 1);
else{
imgList = []
}
You can try to solve it like that.

comparing 2 arrays with _.difference

Im using lodash with some calculations, but there is a function that isnt working has i expected, im using for example 'difference'.
His usage is:
_.difference([2, 1], [2, 3]);
output: [1]
But when i apply to my arrays:
_.difference([5111471, 5111513], [5111471,5111505,5111513]);
output:[]
Instead of giving me [5111505], is giving me a empty array.
_.difference returns elements of the first array not present in the second one. There are no such elements in your example, hence the empty result. If you want a symmetric difference (that is, elements that are present in the first array or the second, but not in both), you can do something like
diff = _.union(_.difference(a, b), _.difference(b, a))
_.difference doesn't actually return the difference between two arrays, but instead returns the first array minus the second. So to return [5111505] you need to do:
_.difference([5111471,5111505,5111513],[5111471, 5111513]);
See documentation for more info:
https://lodash.com/docs/4.15.0#difference

javascript splice skipping element- why this behaviour

I was working with splice within a nested for loop and I came across a behaviour I could not understand.
var a = [0, 1, 2, 3, 4];
for (b in a) {
console.log(a);
for (c in a) {
console.log(c + '==' + a[c]);
if (c === "1")
a.splice(c, 1);
}
}
console.log(a);
Its output is strange
[0, 1, 2, 3, 4]
"0==0"
"1==1"
"2==3" // why is index 2 referring to value 3 , whereas it should refer to 2
"3==4"
[0, 2, 3, 4]
"0==0"
"1==2"
"2==4" // index 2 referring to value 4 , whereas it should refer to 3
[0, 3, 4]
"0==0"
"1==3"
[0, 4]
I am splicing index 1 and it is skipping the next element .
Why this Behaviour ...
Here checkout : http://jsbin.com/isahoj/3/edit
EDIT:
ok , I understand that it shifts the index after splicing , but I am calling splice after doing console.log()... so how is it spliced earlier?
why is index 2 referring to value 3 , whereas it should refer to 2
Because on the previous iteration, you removed an entry via splice:
if (c==="1")
a.splice(c, 1);
...so everything shifted up (that's what splice does). Then the next loop continues with c being "2", and the entry (now) at index 2 is 3.
Re your comment:
ok , I understand that it shifts the index after splicing , but I am calling splice after doing console.log()... so how is it spliced earlier?
Okay, let's step back:
Before the inner loop starts, a looks like this:
[0, 1, 2, 3, 4]
On the first pass of your inner loop, c is "0" and the entry at index 0 is 0, so your log statement shows "0==0". splice is not called, and a is not changed, so it still looks like this:
[0, 1, 2, 3, 4]
On the next pass of your inner loop, c is "1", and the entry at index 1 is 1, so your log statement shows "1==1". Then splice is called, changing a so it looks like this:
[0, 2, 3, 4]
On the next pass of your inner loop, c is "2", and the entry at index 2 is 3 (not 2, because a has changed), so your log statement shows "2==3".
Later, when your outer loop runs again, c is again "1" at one point, so another entry gets removed and you see the same effect.
What you should do is actually watch the code run live, single-stepping through with the debugger, and watching how a changes in real time. All modern browsers have capable debuggers built in, you don't have to litter your code with console.log statements, you can actually watch what happens.
It's not the reason for your problem, but note that for-in isn't for looping over array indexes, it's for enumerating the property names of an object (which is why your c==="1" comparison works, property names are always strings). More: Myths and realities of for..in
After you remove element 1, then "a" looks like:
[0, 2, 3, 4]
The new element 1 is 2. The next iteration of the loop, then "c" is 2, and a[2] is indeed 3.
You should not use for…in-enumerations to loop arrays.
That said, your problem is that the .splice method modifies your array, removing an item and adjusting indizes after it. Yet, you do not adjust your iteration variable, so it will skip the index - the old index "1" was visited already, next will be "2" not the new "1" again.
To solve this, you can either loop backwards or decrease the iteration counter by the number or removed items. However, when revisiting the index your condition would always be fulfilled, and you are successively removing all second elements from the arrays until there is no second element left - not sure whether this is your goal.

Categories