Mini linter step 3, passing arrays as arguments into functions, function scope issue?

Hello Codecademy,

I’m working on the JS mini linter project and have a question about two functions I wrote. The first (miniLinter101) works as expected, and is a solution to the third step in the mini linter project. As for the second function (miniLinter102), I expected it to work in exactly the same way as the first function, but it does not. My question is: Why doesn’t my second function work the same way as my first function?

Here’s the context:

let story = 'Last weekend, I took literally the most beautiful bike ride of my life. The route is called "The 9W to Nyack" and it actually stretches all the way from Riverside Park in Manhattan to South Nyack, New Jersey. It\'s really an adventure from beginning to end! It is a 48 mile loop and it basically took me an entire day. I stopped at Riverbank State Park to take some extremely artsy photos. It was a short stop, though, because I had a really long way left to go. After a quick photo op at the very popular Little Red Lighthouse, I began my trek across the George Washington Bridge into New Jersey.  The GW is actually very long - 4,760 feet! I was already very tired by the time I got to the other side.  An hour later, I reached Greenbrook Nature Sanctuary, an extremely beautiful park along the coast of the Hudson.  Something that was very surprising to me was that near the end of the route you actually cross back into New York! At this point, you are very close to the end.';

let overusedWords = ['really', 'very', 'basically'];

let unnecessaryWords = ['extremely', 'literally', 'actually' ];

let storyWords = story.split(' ');

let betterWords = [];

Next is my first function. It takes two arrays as arguments, filters one out of the other, and then returns a third which is saved to a variable outside of the scope of the function.

function miniLinter101(array01, array02) {
  return array01.filter(word => array02.includes(word) != true);
}

betterWords = miniLinter101(storyWords, unnecessaryWords);
console.log(betterWords.length); // => 182

Next is my second function. I try to assign the “linted” array to an array variable passed into the function itself. But it seems to never get assigned. I’m not sure what’s happening/not-happening here. As I mentioned above, I expected miniLinter102 to do the same thing as miniLinter101, but it doesn’t. Why? What am I missing here?

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
}

miniLinter102(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 0

Thank you in advance for any help.
~S

Hi @eddyfletch and welcome to the forum!

array03 = array01.filter(word => array02.includes(word) != true);
//^^^

The difference is that you don’t assign the filtered words to the variable betterWords as you do in your first approach.
array03 is only available within your function scope and you don’t return it.
Since betterWords is a let, you could reassign betterWords by replacing array03 with betterWords within your second function.

Thank you for responding @mirja_t !

I still do not understand, but your response is helping me narrow down where exactly my misunderstanding is.

You say that I don’t assign the filtered array to the variable betterWords in my second function miniLinter102. Up until reading your response I was certain that I had.

How I envisioned the function miniLinter102 working with regards to the filtered array and the betterWords variable is as follows:
The third parameter in the function miniLInter102 is labeled array03. Since I am passing the array betterWords as the argument for the third parameter I expected the function to use betterWords in place of the label array03. I see this happening with array01 and array02. In the function call

miniLinter102(storyWords, unnecessaryWords, betterWords);`

the function miniLinter102 recognizes that array01 is storyWords, and ALSO that array02 is unnecessaryWords. I expected miniLinter102 to recognize that array03 is betterWords… but it does not.

Why doesn’t miniLinter102 recognize that array03 is betterWords and therefore assign the filtered array to it?

Again, thank you for your response @mirja_t .

I’m not a 100% sure where the cause of the misunderstanding is, but I’ll try to narrow down step by step what you did differently in the first function. Hope it helps:

  return array01.filter(word => array02.includes(word) != true);

One major difference is that you use the return keyword. If you leave it, the array from array01.filter(word => array02.includes(word) != true); would only be available within your function scope. For example:

function miniLinter101(array01, array02) {
   console.log(array01.filter(word => array02.includes(word) != true));
}
miniLinter101(storyWords, unnecessaryWords);

That would log the array to the console.
But this:

function miniLinter101(array01, array02) {
   array01.filter(word => array02.includes(word) != true);
}
console.log(miniLinter101(storyWords, unnecessaryWords));

Would log ‘undefined’.

You don’t necessarily have to use the return keyword.
You could also do:

const betterWords = [];

function miniLinter101(array01, array02) {
   betterWords.push(array01.filter(word => array02.includes(word) != true));
}
miniLinter101(storyWords, unnecessaryWords);
console.log(betterWords); // logs a nested array with 182 words

But that would lead to a nested array.

Then there is the third option to reassign the array:

let betterWords = [];

function miniLinter101(array01, array02) {
   betterWords = array01.filter(word => array02.includes(word) != true);
}
miniLinter101(storyWords, unnecessaryWords);
console.log(betterWords.length); // 182

For this option your betterWords variable must be declared as a let (what you did). You can push to a const, but not reassign it.

Here:

You pass betterWords to your function, but it never gets out.

If you do:

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
  console.log(array03.length); // 182
}

miniLinter102(storyWords, unnecessaryWords, betterWords);

You see that array03 has a valid value inside your function body. But this:

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
}

console.log(miniLinter102(storyWords, unnecessaryWords, betterWords)); // undefined

Will log ‘undefined’.

1 Like

Hello @mirja_t , and thank you again for working through this with me.

This section of your response is getting close to helping clarify my misunderstanding:
regarding the function miniLinter102:

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
}

miniLinter102(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 0

You wrote-
~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
miniLinter102(storyWords, unnecessaryWords, betterWords);

You pass betterWords to your function, but it never gets out.
~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~

What do you mean “it never gets out.”?

I don’t necessarily want it to “get out”. I am aware that miniLinter102 does not returning anything. I am not trying to return something. I want to assign the new filtered array to the variable betterWords inside the function by passing betterWords into the function as an argument.
.
.
.
Please bear with me as I try to articulate what information I’m looking for. I hope these two examples will help explain where and why I’m confused:

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
}

miniLinter102(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 0
console.log(betterWords.length); // => 0


function miniLinter103(array01, array02) {
   betterWords = array01.filter(word => array02.includes(word) != true);
}

miniLinter103(storyWords, unnecessaryWords);
console.log(betterWords.length); // => 182

In miniLinter102, betterWords does not “get out” of the function. It was passed into the function as the third argument but then seems to be stuck there? Maybe?

In miniLinter103 however betterWords does “get out” of the function. betterWords was assigned a new array within the function, but that change is still accessible outside of the function after the function call has finished executing. I don’t understand why betterWords was able to “get out” of miniLinter103 while it wasn’t able to in miniLinter102.
.
.
.
I tried out this third situation based on one of the examples in your last response (thank you for so many examples @mirja_t !).

console.log(betterWords.length); // => 0

function miniLinter104(array01, array02, array03) {
   array03.push(array01.filter(word => array02.includes(word) != true));
}

miniLinter103(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 1

In this example, miniLinter104, I pass betterWords into the function call as the third argument (parameter array03) and the filtered array is effectively “pushed” into betterWords (I am aware that it is nested). In this example betterWords was able to “get out”.

What is stopping betterWords from being able to “get out” of miniLinter102? Does it have something to do with the properties of the assignment operator = in javascript? Is it something about the assignment operator AND function scope? and most importantly, Am I being clear in my examples and questions?

Thank you
~S

Hi @eddyfletch
I think I understand your problem. Not sure if I can solve it, but I’ll try:
You’re passing your betterWords Array to a function parameter called array03. Whatever you do with the original array betterWords inside your function is stored in the variable name array03 (but you’re not even doing anything with it). If you want betterWords to be array03, you have to tell it somewhere. Either by overwriting (reassigning) it inside your function as in this example:

function miniLinter103(array01, array02) {
   betterWords = array01.filter(word => array02.includes(word) != true);
}

or reassigning it to betterWords outside of your function as in this example:

function miniLinter103(array01, array02) {
   return array01.filter(word => array02.includes(word) != true);
}
betterWords = miniLinter103(storyWords, unnecessaryWords);

In your function, you’re passing betterWords as an argument to the parameter array03. But then you’re overwriting it with array01.filter(word => array02.includes(word) != true);. Actually, you’re doing nothing with betterWords inside your function, so whether passing it into your function doesn’t make a difference in the first place.

Hello again and thank you for your response,

In this example below, the function recognizes that I passed storyWords as array01, and it also recognizes that unnecessaryWords is array02.

function miniLinter103(array01, array02) {
   return array01.filter(word => array02.includes(word) != true);
}
betterWords = miniLinter103(storyWords, unnecessaryWords);

In this next example the function does recognize that array03 is betterWords. (the arrays become nested, yes, but it “works”)

console.log(betterWords.length); // => 0

function miniLinter104(array01, array02, array03) {
   array03.push(array01.filter(word => array02.includes(word) != true));
}

miniLinter103(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 1

Something else is happening in this next function and that’s where I’m stuck.

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
}

miniLinter102(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 0

You said:

In your function, you’re passing betterWords as an argument to the parameter array03. But then you’re overwriting it with array01.filter(word => array02.includes(word) != true); . Actually, you’re doing nothing with betterWords inside your function, so whether passing it into your function doesn’t make a difference in the first place.

I believe you when you say that I’m doing nothing with betterWords inside the function. I believe you because nothing is happening. I expected the function to “know” that I pass an array(betterWords) into the third parameter array03 and then to reassign that array with a new array, the new filtered array.

Why isn’t this:

function miniLinter102(array01, array02, array03) {
  array03 = array01.filter(word => array02.includes(word) != true);
}

miniLinter102(storyWords, unnecessaryWords, betterWords);
console.log(betterWords.length); // => 0

the same as putting betterWords directly into the function like this

betterWords = [];

function miniLinter102(array01, array02) {
  betterWords = array01.filter(word => array02.includes(word) != true);
}

miniLinter102(storyWords, unnecessaryWords);
console.log(betterWords.length); // => 182

betterWords can be mutated (.push()) when passed into the function as an argument. betterWords can be reassigned the new filtered array when typed directly into the function (betterWords = array01.filter(word => array02.includes(word) != true);). Why isn’t betterWords reassigned the new filtered array when passed into the function as an argument? This feels like I’m missing something very simple… Something like a basic JS rule about arrays or parameters or variable assignment or something…

Again, thank you for corresponding with me.
~S

This does not work unless you declared a variable array03 outside of the function and assigned it to an empty array.
If you console.log(betterWords) I’m sure it’ll log the same empty array you originally declared.The above function didn’t do anything, because it can’t find the item to be pushed to. You don’t even call miniLinter104();

Because you’re not telling betterWords that it is supposed to be array03. Either by betterWords = array03 or betterWords.push(array03) If I were you I wouldn’t know until you tell me :wink:

Imagine betterWords to be a bucket: betterWords.push() is pouring stuff in it. You can imagine array03 and betterWords to be two buckets standing next to each other. And until you pour the content from bucket array03 to the bucket betterWords, the bucket betterWords is empty.

I remember that I had a hard time understanding the basic principle of passing arguments to a function. Once it clicks, you’ll have the same hard time understanding what the original problem was. The fog will lift :wink:

Edit: ______________
Just as an addition to the bucket example: When you pass betterWords as an argument to your function, you’re pouring the content of betterWords in the array03 bucket. You’ll have to pour it back to betterWords. One way or the other.

Hi @mirja_t, thank you again for responding and working with me on this. I’m sorry about the code typos in my last correspondence. They clouded my meaning and intent. I’ve retyped up a block of code (below) because I’m getting confused with all these miniLinter1000000000s. My questions haven’t changed, but hopefully this block of code doesn’t have any typos and hopefully I explain myself clearly.

let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let evenNums = [2, 4, 6, 8, 10];
let filteredNums = [];

function numFilter01(array01, array02) {
  filteredNums = array01.filter(num => array02.includes(num) != true);
}

function numFilter02(array01, array02, array03) {
  array03 = array01.filter(num => array02.includes(num) != true);
}

function numPush(array01, array02, array03) {
  array03.push(array01.filter(num => array02.includes(num) != true));
}

console.log(filteredNums); // -> [ ]

numFilter01(nums, evenNums);
console.log(filteredNums); // -> [ 1, 3, 5, 7, 9 ]

filteredNums = [];

numFilter02(nums, evenNums, filteredNums);
console.log(filteredNums); // -> [ ]

filteredNums = [];

numPush(nums, evenNums, filteredNums);
console.log(filteredNums); // -> [ [ 1, 3, 5, 7, 9 ] ]

I pass filteredNums as an argument into both the function calls numFilter02(nums, evenNums, filteredNums); and numPush(nums, evenNums, filteredNums);. filteredNums is mutated in one instance but not the other. Why?

I think I’ve got what you meant and answered it anyway. My bucket examples should work for these examples as well.

In your examples 2 and 3 you pass filteredNums to the parameter array03. Inside the function filteredNums is known as array03. Outside the function it isn’t. Whatever you do with array03 stays inside the function unless you reassign it to filteredNums or push to it.

I can’t think of a better example than the bucket example. If that doesn’t help I run out of ideas :frowning:

Hello and thank you again @mirja_t,

The bucket example is a cute metaphor, but it isn’t the explanation I’m looking for. I want to know what’s actually happening.

Whatever you do with array03 stays inside the function unless you reassign it to filteredNums or push to it.

I added a new function to the block of code, numPop(), and it mutates the array just like numPush() does.

let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let evenNums = [2, 4, 6, 8, 10];
let filteredNums = [];

function numFilter01(array01, array02) {
  filteredNums = array01.filter(num => array02.includes(num) != true);
}

function numFilter02(array01, array02, array03) {
  array03 = array01.filter(num => array02.includes(num) != true);
}

function numPush(array01, array02, array03) {
  array03.push(array01.filter(num => array02.includes(num) != true));
}

function numPop(array01) {
  array01.pop();
}

console.log(filteredNums); // [ ]

numFilter01(nums, evenNums);
console.log(filteredNums); // [ 1, 3, 5, 7, 9 ]

filteredNums = [];

numFilter02(nums, evenNums, filteredNums);
console.log(filteredNums); // [ ]

filteredNums = [];

numPush(nums, evenNums, filteredNums);
console.log(filteredNums); // [ [ 1, 3, 5, 7, 9 ] ]

console.log(nums); // -> [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
numPop(nums);
console.log(nums); // -> [ 1, 2, 3, 4, 5, 6, 7, 8 ]

Taking your explanation further: " Whatever you do with array03 stays inside the function unless you reassign it to filteredNums or push to it." we can then add an “OR if you .pop() to it” and then also an “OR if you .shift() to it”… and so on and so forth.

I have been continuing my work in the JS course and came upon this:

https://www.codecademy.com/courses/introduction-to-javascript/lessons/objects/exercises/pass-by-reference

Pass By Reference

Objects are passed by reference . This means when we pass a variable assigned to an object into a function as an argument, the computer interprets the parameter name as pointing to the space in memory holding that object. As a result, functions which change object properties actually mutate the object permanently (even when the object is assigned to a const variable).

This gives me new language to describe my understanding of what’s happening.

filteredNums is pointing to an array. I pass filteredNums into a function call as an argument and now all references to that parameter (array03 in numFilter02()) are also pointing to that same array . If within the function I call a mutation operation on that parameter (array03) such as .push() or .pop() then the array is mutated. Since the variable filteredNums is still pointing to that same array, when I console.log() filteredNums it logs the mutated array… this is my current understanding of what’s going on with numPush() and numPop().

The answer to my original question regarding what’s happening with numFilter01() and numFilter02() and why they aren’t producing the same result still eludes me. My current plan is to continue on with the coursework and hopefully I stumble upon the answer itself or upon something that leads me to it. If I do not then I plan on reformatting my question with new insight and more accurate language and then posting it again to the forums.

Thank you @mirja_t for working through this with me. You have helped me immensely in being able to pinpoint where exactly my misunderstanding is and isn’t. Maybe we’ll meet again in a future forum; I’d like that.

Sincerely,
~S

Hi @eddyfletch

:scream: Looks like the bucket example not only wasn’t what you have been looking for, but it’s simply been wrong!

I never tried to pass an array I wanted to mutate and which I had declared and assigned outside the function scope to a function, but always directly referenced the array instead. I was so convinced that your examples in the most recent posts don’t have an effect on the array, that I didn’t confirm it.

Sorry for the confusion I caused here :frowning:
And thanks for the link. I finished all JS content on codecademy and must have missed that.

See you another time here when I ask you for some enlightenment!