I'm very new to javascript and have just recently learned about For loops. I have a variable that consists of an array containing a bunch names, and I would like to add last names to each of them. I wrote the code as shown below and have a few questions.
let name = ["john", "maria", "brandon", "gaby", "jessica", "angel"];
function addLastName(array) {
for (let i = 0; i < array.length; i++) {
console.log(name[i] + " (please insert last name)")
}
}
console.log(addLastName(name))
Result :
john (please insert last name)
maria (please insert last name)
brandon (please insert last name)
gaby (please insert last name)
jessica (please insert last name)
angel (please insert last name)
undefined
Questions:
About the second statement for the loop. Correct me if I'm wrong, but when using length in an array, it will show the amount of data inside the array right? So in this case, name.length = 6. But to my understanding, when accessing a part of an array, the count always starts at 0. So I used array.length-1. But the result didn't show "Angel". When I used array.length, the result showed Angel. What logic am I missing here?
When I put the result on the console, there's always an "undefined" at the end of it, whether I used array.length or array.length-1. Can anybody tell me why it showed up?
For your first question:
Inside the for loop, if you start from 0, and the condition is i < array.length and the length of the array is 6, it will go from 0 to 5, and when it reaches 6 it will not respect the condition (6 < 6 false) so it will exit the for loop before executing the block inside (but when you exited the for, i will be 6).
For your second question:
You should not call console.log(addLastName(name)) because addLastName already logs to the console. That console.log is the one that prints undefined since it will print the result of the function, which is undefined by default if you do not return anything inside the function.
Related
I'm currently working through freeCodeCamp's JS course.
One of the last problems asks you to create a recursive function that only accepts one argument n and creates an array that counts down from n to 1.
I was able to solve the problem using this code (SPOILERS IF YOU ARE ALSO WORKING ON THIS PROBLEM):
// Only change code below this line
function countdown(n) {
if (n < 1) {
return [];
} else {
const countArray = countdown(n - 1);
countArray.unshift(n);
return countArray;
}
}
// Only change code above this line
// my test
console.log(countdown(1))
I mostly arrived at this answer by copying syntax in the provided example. I plugged my answer into Python Tutor's code visualizer here. I will be referencing the steps in this visualizer.
Question about step 3: I notice it says countArray (block 1) is undefined. I assume this is because the function is hanging onto n and will go back and populate the array once the base statement creates it? Does this mean the defining of the array is delayed until the base case is reached?
Question on step 6: I see that my code worked as intended and now that n is 0, the base case is activated and the function returns an empty array. How does the code know that I want to populate this empty array with countArray? What ties the two together.
Question on step 7: If you can only answer one of my questions, I would like it to be this one.: Why does the function continue at all after the base case was reached (when n = 0)? From my flawed understanding return ends the function immediately. By this logic, my code shouldn't do what is intended. It would always count n down, and then regardless return an empty array.
Thank you for reading my question. If my thoughts are not detailed clearly enough here, please let me know how I can clarify.
Recursive function calls are stacked on top of the previous call.
So taking an example of countdown(2),
n > 0, i.e run else part which saves the value returned by countdown(1).
So now we go to countdown(1), which sends us to countdown(0).
Now, countdown(0) returns us an empty array.
From here, we run the left over part of countdown(1), i.e countArray = [] , which we got from countdown(0)
unshift means push value at start of array. So now our array is countArray=[1]
We return this value to countdown(2) (the first line). And now our countArray = [1] is in our initial function call.
Then we run the left over part again: countArray.unshift(2) -> [2, 1]
And finally we return it to whatever called it.
// Call Stack:
countdown(2) -> countdown(1) -> countdown(0)
// return Stack:
[2, 1] <- [1] <- []
Bonus: below is a one liner for the required function
const countdown = (n) => n ? [n, ...countdown(n - 1)] : []
console.log(countdown(5))
No array is created until you reach the base case.
When you call a function, a new context with its own local variables (called a stack frame) is created. Your visualizer shows these on the right ("Frames").
Notice how a new frame appears going from step 3 to 4. Then, when the base case returns going from step 6 to 7, the frame disappears again. The execution picks up where it left off before evaluating the base case, with the only difference being that the value for countArray is known.
return only finishes the current context, returning the intermediate result to its parent context. Basically, each level of recursion is independent here.
const rapperArray = ['Tupac', 'Jay-Z', 'Notorious B.I.G', 'Kendrick Lamar']
for (let i = 0; i < rapperArray.length; i++) {
console.log(rapperArray[i]);
if (i === 2) {
break;
}
}
console.log("And if you don't know, now you know.");
So how does i work in that console.log( rapperArray[ i ] );? I know that it accesses the elements in the array but I can't seem to get my head around how it actually functions.
The i is a variable. In a for loop, you have the following syntax:
for(initialization; condition; update) {
// for loop body
}
The for loop will begin by running the initialization portion first, which in this case declares the variable i with an initial value of 0. Before each iteration of the loop, condition is checked and the loop body will run as long as condition is true. Then, after the loop body runs, update will run. In this case, the variable i will have its value incremented by 1, i.e. i++ is basically the same thing as i += 1.
In other words, the for loop will use every value of i from 0 up until rapperArray.length - 1. So console.log(rapperArray[i]); will be the same as console.log(rapperArray[0]); in the first iteration, console.log(rapperArray[1]); in the second iteration, and so on.
You can see this more clearly by running the following:
const rapperArray = ['Tupac', 'Jay-Z', 'Notorious B.I.G', 'Kendrick Lamar'];
for (let i = 0; i < rapperArray.length; i++) {
console.log('When i is ' + i + ', rapperArray[i] is ' + rapperArray[i] + '.');
}
A for loop header consists of three parts:
Initial state let i = 0
Condition to check if loop should continue i < length
Increment per run i++
We start with 0, in the beginning i is lower than length, then we up it by 1 (i++ increases i by 1), if it's still lower than length - we continue until i has the same value as length and then we stop.
It indicates the current iteration of the loop. For each iteration, i is incremented. When used to get an array item, it represents the index of the item to retrieve from the array. You can read more about indexed collections here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
Arrays in JavaScript are zero-index based, which means the first index is always zero. And they increment from there. Arrays are ordered collections, so the item at the first index (zero) is always the same, and so on.
If you have a list on paper in front of you, you may number the lines starting with 1 and going up from there. Each item in an array is somewhat like each line on that piece of paper, only the line numbers start at zero instead of one. If you want to get line n from the paper, you find the line numbered n and there you go.
I want to reverse an array that I input into a function.
But for some reason the console returns the first value of the array instead of taking the full array within the while loop so it can unshift the value at the end to the front then delete that same value.
function littleWHEW(lemonade) {
let i = lemonade.length - 1;
while (i >= 0) {
lemonade.unshift(lemonade[i])
lemonade.pop(lemonade[i])
i = i - 1
}
return lemonade
}
console.info(littleWHEW([1,2,3,4,5]))
Just use the
reverse()
method:
function littleWHEW(lemonade) {
return lemonade.reverse();
}
You should not add a parameter to the pop() method, by the way.
Since you asked for explanation, let's take a deep investigation. Before we do, please take a look at
unshift and pop
Firstly i = 4. Here're what happens in one loop:
[1,2,3,4,5] is the original array. lemonade.unshift(lemonade[i]) adds one element to the first position of lemonade. At this point i = 4 so lemonade[4] = 5, we have [5,1,2,3,4,5] (notice the bold).
Now you pop the last one out. [5,1,2,3,4,5] becomes [5,1,2,3,4].
You decrease i.
Now i = 3, And here're what happens in second loop:
[5,1,2,3,4] is the original array. lemonade.unshift(lemonade[i]) adds one element to the first position of lemonade. At this point i = 3 so lemonade[3] = 3, we have [3,5,1,2,3,4] (notice the bold).
Now you pop the last one out. [3,5,1,2,3,4] becomes [3,5,1,2,3].
You decrease i.
After one loop, your i does not point to the last element as expected, and makes things wrong (as second loop does).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
In a JavaScript project I was looping through a list and sometimes removing the current element with splice(). Now after that obviously the iterating variable need be decremented to not miss an element. Looks like this:
for (var i = 0; i < list.length; ++i) {
if (...){
list.splice(i,1);
--i
}
}
Now, coming from Java, I figured I'd save a line by decrementing the variable after passing it as an argument like this:
for (var i = 0; i < list.length; ++i) {
if (...)
list.splice(i--,1)
}
The answers show that it should work.
The issue happened using paper.js - I opened an issue on github for that. It seems that paper.js was decrementing i before passing its value to splice() resulting in an actual call of splice(-1,1). With an index of -1, splice() would remove the list's last item. On the next loop iteration, i would be incemented back to 0, the check on list[0] would still evaluate to true as the element is still there, the same call splice(-1,1) would happen deleting the last element, and so on.
See the broken behavior here: Tapping keys creates circles which shrink and, when below area 1, are removed from canvas and the array holding them. The issue happens when splice() gets called in line 17.
Quite curious, that issue - thanks for the help!
No difference between two ways (decrementing i argument on splice call or in the next line) because you are using a post-decrement operator.
By post-decrement I mean when the -- operator is used as a postfix (i.e. i--): in this case it returns the current value before decrementing. And, that's why both alternatives used in your questions are equivalents.
Regarding to type of i variable, you can check with typeof operator. In this case is a number object, which belongs to the scalar primitive group (Number, String, Boolean, undefined, null, Symbol). All primitive values are assigned by value. Only compound values in javascript are assigned by reference (Object, Array).
You can read more about javascript arithmetic operators.
Check the outputs for the two cases:
function test(list, condition) {
const list1 = [...list];
for (var i = 0; i < list1.length; i++) {
if (condition(list1[i], i)) {
list1.splice(i--, 1);
}
}
console.log('output using decrement on splice arg', list1);
const list2 = [...list];
for (var i = 0; i < list2.length; i++) {
if (condition(list2[i], i)) {
list2.splice(i, 1);
i--;
}
}
console.log('output decrementing after splice', list2);
}
const list = [1, 2, 3, 4];
test(list, (elem, index) => elem % 2 === 0);
// -> [1, 3]
// -> [1, 3]
test(list, (elem, index) => index % 2 !== 0);
// -> [1]
// -> [1]
The problem I see with your code is with the if condition inside the loop. If your test includes the index in some way that could cause you to remove extra elements (not intended in the first place).
Second example, using use a condition based on the element indexes, and exemplifies a possible situation when we try to remove all elements on odd positions. This happens because on the second iteration (i=1) the tests evaluates to true and the decrement of i-- steps back to zero (i=0). Then the for increment acts and again we are testing the previous scenario: i=1.
Previous behavior remains the same whether you decrement the iteration variable inline in the splice call or after.
I got a problem with this simple piece of code which i cant figure out.
Instead of printing the whole array in the console, i get the message "10 undefined". Altough if i put "var i" to 0 or below then it's all good and i get a full list from that number up to 10.
Why wont this work when "i" is set to a number above 0?
Took a picture of my console in chrome to show how it looks like:
var ar = [];
for (var i = 1; i <= 10; i++) {
ar.push(i);
console.log(ar[i]);
}
JavaScript array indices start at 0, not 1. The .push() method adds an element at the end of the array, which in the case of an empty array (as yours is when your loop begins) will be array element 0.
Your loop inserts the value 1 at array index 0, the value 2 at array index 1, and so forth up to the value 10 at array index 9.
Each of your console.log(ar[i]) statements is trying to log a value from an index one higher than the highest element index, and those elements will always be undefined. So the console logs the value undefined ten times.
You can log the last element of an array like this:
console.log(ar[ar.length-1]);
Or in your case where you (now) know that i will be one higher than the index that .push() used:
console.log(ar[i-1]);
"10 undefined" means that the console showed "undefined" 10 times.
As thefourtheye says in his comment, you're pushing the value i but the index of the element that you just pushed onto the end of the array is i - 1. This means that each time you console.log(ar[i]) you're logging something that's not yet defined.
This is all because the first element in the array is ar[0], not ar[1]. You can fix your problem by logging like so: console.log(ar[ i - 1 ]);
Because array indices start at zero. The current index is undefined that's why you get those. Try this instead:
var ar = [];
for(var i = 1;i <= 10;i++){
ar.push(i);
console.log(ar[i-1]);
}