1) What’s the output?
function sayHi() {
console.log(name);
console.log(age);
var name = 'Lydia';
let age = 21;
}
sayHi();
Inside the function, the name
variable is declared using the var
keyword. This causes the variable to be hoisted, meaning JavaScript allocates memory for it during the creation phase. However, it is initialized with undefined
until the execution reaches the assignment statement. If we attempt to log name
before its declaration, it will output undefined
since it hasn’t been assigned a value yet.
On the other hand, variables declared with let
and const
are also hoisted, but they are not automatically initialized. They remain in a “temporal dead zone” from the start of the block until their declaration is encountered. Accessing them before initialization results in a ReferenceError
, as JavaScript enforces stricter scoping rules for let
and const
.
2) What’s the output?
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
Output : 3 3 3
and 0 1 2
Due to JavaScript’s event queue, the setTimeout
callback function executes only after the loop has completed. In the first example, where i
is declared with var
, it is function-scoped (or globally scoped if declared outside a function). The loop increments i
on each iteration, and by the time setTimeout
runs, i
has already reached 3. As a result, every setTimeout
callback logs the final value of i
rather than the expected loop values.
In contrast, when i
is declared using let
, it is block-scoped. Each iteration creates a new i
variable, confined to that specific loop cycle. This ensures that each setTimeout
callback captures the correct value of i
at the time of its iteration, leading to the expected behavior where the values are logged sequentially as intended.
3) What’s the output?
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius,
};
console.log(shape.diameter());
console.log(shape.perimeter());
Note that the value of diameter
is a regular function, whereas the value of perimeter
is an arrow function.
With arrow functions, the this
keyword refers to its current surrounding scope, unlike regular functions! This means that when we call perimeter
, it doesn’t refer to the shape object, but to its surrounding scope (window for example).
Since there is no value radius
in the scope of the arrow function, this.radius
returns undefined
which, when multiplied by 2 * Math.PI
, results in NaN
.
4) What’s the output?
+true;
!'Lydia';
The unary plus tries to convert an operand to a number. true
is 1
, and false
is 0
.
The string 'Lydia'
is a truthy value. What we’re actually asking, is “Is this truthy value falsy?”. This returns false
.
5) Which one is true?
const bird = {
size: 'small',
};
const mouse = {
name: 'Mickey',
small: true,
};
- A:
mouse.bird.size
is not valid - B:
mouse[bird.size]
is not valid - C:
mouse[bird["size"]]
is not valid - D: All of them are valid
A is not a Valid answer
6) What’s the output?
let c = { greeting: 'Hey!' };
let d;
d = c;
c.greeting = 'Hello';
console.log(d.greeting);
In JavaScript, all objects interact by reference when setting them equal to each other.First, variable c
holds a value to an object. Later, we assign d
with the same reference that c
has to the object. Answer is Hello
7) What’s the output?
let a = 3;
let b = new Number(3);
let c = 3;
console.log(a == b);
console.log(a === b);
console.log(b === c);
new Number()
is a built-in function constructor. Although it looks like a number, it’s not really a number: it has a bunch of extra features and is an object. When we use the ==
operator (Equality operator), it only checks whether it has the same value. They both have the value of 3
, so it returns true
. However, when we use the ===
operator (Strict equality operator), both value and type should be the same. It’s not: new Number()
is not a number, it’s an object. Both return false.
Answer is true false false
8) What’s the output?
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
return this.newColor;
}
constructor({ newColor = 'green' } = {}) {
this.newColor = newColor;
}
}
const freddie = new Chameleon({ newColor: 'purple' });
console.log(freddie.colorChange('orange'));
The colorChange
function is static. Static methods are designed to live only on the constructor in which they are created, and cannot be passed down to any children or called upon class instances. Since freddie
is an instance of class Chameleon, the function cannot be called upon it. A TypeError
is thrown.
9) What happens when we do this?
function bark() {
console.log('Woof!');
}
bark.animal = 'dog';
This is possible in JavaScript, because functions are objects! (Everything besides primitive types are objects)
A function is a special type of object. The code you write yourself isn’t the actual function. The function is an object with properties. This property is invocable.
10) What’s the output?
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const member = new Person('Lydia', 'Hallie');
Person.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};
console.log(member.getFullName());
In JavaScript, functions are objects, and therefore, the method getFullName
gets added to the constructor function object itself. For that reason, we can call Person.getFullName()
, but member.getFullName
throws a TypeError
.
If you want a method to be available to all object instances, you have to add it to the prototype property:
Person.prototype.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};