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}`;
};