As part of my journey to become a better JavaScript programmer, I need to dive deep into JavaScript foundations. In this article, I'll show you mind-boggling questions (for me, it was mind-boggling, I hope for you as well) that we can learn some of the concepts behind these questions.
Before we start, I want to mention some of the resources I used for writing this article, and I highly recommend you to use them as well:
- 70 JavaScript Interview Questions - Excellent article that you can learn a lot about JavaScript foundations.
- What Makes Javascript Weird...and AWESOME - I found this Youtube playlist, In my opinion, the explanations are very understandable, and he shows visual code examples.
- What the heck is the event loop anyway? | Philip Roberts | JSConf EU - One of the most famous JavaScript videos recently. He explains how JavaScript works "Behind the scenes" (how the event loop works).
Of course, this is only some of the resources on the subject. There are many other resources to learn from.
So are you ready to get your mind blow away (from JavaScript question)?
Questions
Notice 1!: To each question, there is an answer with an explanation (link below each item).
Notice 2!: If you run the questions on the console, remember that some of the variables are repeating themselves, so do refresh from question to question.
Notice 3!: For each question think what will be the output.
Question 1
var a = 1
function foo(){
var a = 2
console.log(a)
}
foo()
console.log(a);
Go to answer 1
Question 2
function foo(){
a = 2
}
foo()
console.log(a);
Go to answer 2
Question 3
var answer = 0;
const baseValue = value => multipleValue => value * multipleValue;
const multiple = baseValue(2);
answer = multiple(5);
console.log(answer);
Go to answer 3
Question 4
function outerFunc(outerParam) {
function innerFunc(innerParam) {
outerParam["b"] = innerParam;
}
return innerFunc;
}
const obj = {a:1}
const example = outerFunc(obj);
const answer = example(2)
console.log(obj);
Go to answer 4
Question 5
let arr =[1,2]
function test(array){
array.push(3)
}
test(arr)
console.log(arr)
Go to answer 5
Question 6
let arr =[1,2]
function test(array){
array.push(3)
}
test([...arr])
console.log(arr)
Go to answer 6
Question 7
let arr =[1,2]
function test(array){
array = [1,2,3]
}
test(arr)
console.log(arr)
Go to answer 7
Question 8
const carDetails = {
name: "Tomer",
getName(){
return this.name;
},
};
var name = "Joe";
var getCarName = carDetails.getName;
console.log(getCarName());
Go to answer 8
Question 9
console.log(a)
console.log(b)
var a = 2
let b = 2
Go to answer 9
Question 10
a()
function a(){
console.log("a")
}
b();
var b =function(){
console.log("b")
}
Go to answer 10
Answers
Answer To Question 1
I think the answer is pretty straightforward. If you said 2
and 1
, you are correct. This question is about Scope. In JavaScript, there are two types of scopes: Global Scope and Local Scope, variables declared within a JavaScript function become local, and variables declared outside of the function become global.
The var a = 1
declared out of the function and saved in global memory. The var a = 2
declared inside the function and saved in local memory. it's a different place in memory (even if they have the same name).
Answer To Question 2
If you said a is not defined,
you have healthy thinking, but the answer is 2
. This is why JavaScript is a unique language. According to the logic we talked about in the previous question, the variables should be in local scope, But, if you pay attention, the variables didn't declare (without var
, let
, const
). When we do assignments without declarations in JavaSacript (a=2
), the compiler will save the variable in the global scope. FYI, we can fix this behavior by add "use strict"
.
Answer To Question 3
The answer is 10
. This question is about Closures. In simple words - Closures are functions that return another function, and the inner function has access to the outer variables function (You can read more here). We can look at Closures like Global scope (outer function) and Local scope (inner function) that leaves inside the local scope (baseValue
). Like regular Scope in JavaScript, the Local scope has access to Global Scope. For that reason, the compiler can know what is value
.
FYI, This doesn't seem like a "conservative" Closure example because it's writing in ES5 syntax (arrow function). The "conservative" looks like:
var answer = 0;
function baseValue(value){
return function(multipleValue){
return value * multipleValue;
}
}
const multiple = baseValue(2);
answer = multiple(5);
console.log(answer);
Answer To Question 4
The answer is {a: 1,b: 2}
. After the previous question, we can recognize it's a Closure, but this question is also about References. In JavaScript, there are two kinds of variables types: primitives variables (strings, numbers, and booleans) and References variables (arrays and objects). Primitives variables save in memory in their values, and references save in memory as virtual id. For that reason, when we pass the object from function to function, we actually pass the virtual id. In our case, the compiler saved the obj
and saw we call the reference again by outerParam["b"] = innerParam.
Hence, he added to the object key b
and value 2
(value of innerParam).
In the case of primitives variables like:
function outerFunc(outerParam) {
function innerFunc(innerParam) {
outerParam = innerParam;
}
return innerFunc;
}
const num = 1
const example = outerFunc(num);
const answer = example(2)
console.log(num);
The num
will still be 1
(but the outerParam will be 2).
Answer To Question 5
The answer is [1,2,3]
, arrays are References (full explanation in the previous answer).
Answer To Question 6
The answer is [1,2]
. I used the ES6 "Spread Operator," it's basically the same do test([1,2,3])
. In this way, we created a new array (new reference) and arr
reference saved in different id - we didn't change the reference just added another one.
Answer To Question 7
The answer is [1,2]
. I know that after all the explanations on references, it seems weird. Still, there is a good reason for it, The =
Operator creates a new reference (you can look in this discussion for more information), The array
exist in the local scope and don't influence the global variables in this case.
If the code was like:
let arr =[1,2]
function test(array){
arr = [1,2,3]
}
test(arr)
console.log(arr)
The answer was [1,2,3]
because, in this case, we replaced the global variable (arr
) with a new reference.
Answer To Question 8
The answer is Joe
. The question's subject is "Context"(this
). In JavaScript, this
is the object that is called to the function. When we do var getCarName = carDetails.getName;
we store the function in the global scope, So this will be Window,
and because we set name
in the global scope (window), the output will be Joe
(same as window.name). This is JavaScript's default behavior. If you want to change this behavior, you can use: bind, apply, call, and arrow functions.
Answer To Question 9
If you said undefined
and b is not defined
(error), congratulation, you know Hoisting. In simple words, hoisting is the way the compiler defines the variables. When the function executes, the compiler looks for variables declaration, and if the variable were declared, it would hoist it to the top. it's the same as:
var a;
console.log(a)
a = 2
It only works on var
. let
and const
is not "hoisting" variables. This is why we will see the error: b is not defined.
Answer To Question 10
The answer is a
and b is not a function
(error). This is a very wried part of JavaScript (in my point of view) - functions are hoisted as well. If you read the last answer, you will understand that var
is also hoisted, but it doesn't matter what will be after the =
operator. In the hoisting stage, he will always be undefined
. So when we do b()
, it's the same as undefined().
Thank you for reading this article. I hope you enjoyed and learned new things. If you have any questions or suggestions, please leave a comment.