DEV Community

Cover image for You’re Decent At JavaScript If You Can Answer These 7 Questions Correctly
Lorenz Hofmann-Wellenhof
Lorenz Hofmann-Wellenhof

Posted on • Edited on

You’re Decent At JavaScript If You Can Answer These 7 Questions Correctly

No cheating please πŸ™ƒ

The concepts in these questions are ones I have encountered in production code. The goal of this quiz is to test relevant and essential JavaScript knowledge.

Q1: Understand Context

What will be logged to the console?

const user = {
  name: "Alice",
  isBanned: false,
  pricing: 'premium',
  isSubscribedTo: function(channel) {
    return channel === "JavaScript";
  },
  getName: function() {
    return this.name;
  },
  getStatus: function() {
    const status = () => {
      return `Name: ${this.getName()}, Banned: ${this.isBanned}`;
    };
    return status();
  }
};

const channel = "JavaScript";
const getName = user.getName;
const getStatus = user.getStatus;

console.log(user.getStatus());
console.log(getName());
console.log(getStatus());
Enter fullscreen mode Exit fullscreen mode

Answers:

  • A) Name: Alice, Banned: false, undefined, TypeError: Cannot read property 'getName' of undefined
  • B) Name: Alice, Banned: false, undefined, Name: undefined, Banned: undefined
  • C) Name: Alice, Banned: false, undefined, Name: Alice, Banned: false
  • D) Name: Alice, Banned: false, undefined, TypeError: this.getName is not a function

Q2: Closure

What will be logged to the console?

function createCounter() {
  let count = 0;
  return function() {
    count++;
    console.log(count);
  }
}

const counter1 = createCounter();
const counter2 = createCounter();

counter1();
counter1();
counter2();
Enter fullscreen mode Exit fullscreen mode

Answers:

  • A) 1, 2, 3
  • B) 1, 2, 1
  • C) 1, 1, 1
  • D) 1, 2, undefined

Q3: Asynchronous JavaScript

What will be logged to the console?

console.log('Start');

setTimeout(() => console.log('Timeout 1'), 0);

Promise.resolve().then(() => console.log('Promise 1'));

setTimeout(() => console.log('Timeout 2'), 0);

Promise.resolve().then(() => console.log('Promise 2'));

console.log('End')
Enter fullscreen mode Exit fullscreen mode

Answers:

  • A) Start, End, Timeout 1, Timeout 2, Promise 1, Promise 2
  • B) Start, End, Promise 1, Promise 2, Timeout 1, Timeout 2
  • C) Start, Promise 1, Promise 2, Timeout 1, Timeout 2, End
  • D) Start, Timeout 1, Timeout 2, Promise 1, Promise 2, End

Q4: Prototypes in JS

What will be logged to the console?

function Animal(name) {
  this.name = name;
}

Dog.prototype.speak = function() {
  console.log(`${this.name} makes a sound.`);
}

function Dog(name) {
  Animal.call(this, name);
}

Dog.prototype.constructor = Dog;

const dog = new Dog('Rex');
dog.speak();

console.log(dog instanceof Dog);
console.log(dog instanceof Animal);
Enter fullscreen mode Exit fullscreen mode
  • A) Rex makes a sound., true, false
  • B) Rex makes a sound., true, true
  • C) Error: speak is not a function
  • D) Rex makes a sound., false, true

Q5: Default params

What will be logged for each call?

function displayUserInfo({ name = "Guest", role = "User" } = {}) {
  console.log(`Name: ${name}, Role: ${role}`);
}

displayUserInfo();
displayUserInfo({});
displayUserInfo({ name: "Alice" });
displayUserInfo(null);
Enter fullscreen mode Exit fullscreen mode

Q6: Closure and functions

What will be logged to the console?

const funcs = [];
for (var i = 0; i < 3; i++) {
  funcs.push(function() {
    console.log(i);
  });
}

for (let j = 0; j < 3; j++) {
  funcs.push(function() {
    console.log(j);
  });
}

funcs.forEach(func => func());
Enter fullscreen mode Exit fullscreen mode

Q7: Event Handling and Propagation

document.body.innerHTML = `
  <div id="outer">
    Outer
    <div id="middle">
      Middle
      <button id="inner">Inner</button>
    </div>
  </div>
`;

const outer = document.getElementById('outer');
const middle = document.getElementById('middle');
const inner = document.getElementById('inner');

outer.addEventListener('click', () => console.log('Outer Bubble'), false);
outer.addEventListener('click', () => console.log('Outer Capture'), true);

middle.addEventListener('click', (e) => {
  console.log('Middle Bubble');
}, false);
middle.addEventListener('click', () => console.log('Middle Capture'), true);

inner.addEventListener('click', () => console.log('Inner Bubble'), false);
inner.addEventListener('click', (e) => {
  console.log('Inner Capture');
}, true);

inner.click();
Enter fullscreen mode Exit fullscreen mode
  • A) Inner Capture, Inner Bubble, Middle Capture, Middle Bubble, Outer Capture, Outer Bubble
  • B) Outer Capture, Middle Capture, Inner Capture, Inner Bubble, Middle Bubble
  • C) Inner Bubble, Middle Bubble, Outer Bubble
  • D) Outer Capture, Middle Capture, Inner Capture, Inner Bubble, Middle Bubble, Outer Bubble
  • E) Outer Capture, Middle Capture, Inner Capture, Inner Bubble

You can verify this yourself by pasting the code into the console of the dev tool.

Solution Q1:

The correct answer is D.

Explanation: The user.getStatus() call logs Name: Alice, Banned: false because the arrow function status correctly accesses this within its enclosing scope. However, getName() logs undefined because it loses its this context when assigned to a standalone variable. console.log(getStatus()); throws a TypeError. When getStatus is called without context, this inside it is undefined. The arrow function inside getStatus preserves the this of its surrounding scope (which is now undefined), so when it tries to call this.getName(), it throws an error.

Credit to Samuel Rouse for double checking my answer and correcting it. Thanks!!

Solution Q2:

The correct answer is B.

Explanation: counter1 and counter2 each have their own separate count variables because each call to createCounter() creates a new closure. Thus, counter1 logs 1 and 2 on its first two calls, and counter2 logs 1 on its first call.

Solution Q3:

The correct answer is B.

Explanation: The synchronous console.log calls log "Start" and "End" first. Promises have higher priority than setTimeout in the event loop, so "Promise 1" and "Promise 2" are logged next, followed by "Timeout 1" and "Timeout 2".

Solution Q4:

The correct answer is A.

Explanation: So this one is a bit tricky. The speak method is correctly defined on Dog.prototype, dog is an instance of Dog.

Inside the Dog constructor, this line calls the Animal constructor with the current this context and the name argument. This effectively sets the name property on the newly created Dog instance.

Now let’s say the code would be like this:

// Code before...

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// Code after...
Enter fullscreen mode Exit fullscreen mode

Then the correct answer would be B).

Side note: If you want to verify it yourself you need to paste it into a browser (and not an LLM which gets the answer incorrectly).

Solution Q5:

The correct output is:

  • Name: Guest, Role: User
  • Name: Guest, Role: User
  • Name: Alice, Role: User
  • Some kind of error. Depending on the browser:
  • Chrome, Edge, Arc: Uncaught TypeError: Cannot read properties of null (reading 'name')
  • Firefox: Uncaught TypeError: null has no properties
  • Safari: TypeError: Right side of assignment cannot be destructured

Credit to Samuel Rouse for double checking this in multiple browsers.

Solution Q6:

Answer: 3, 3, 3, 0, 1, 2

Explanation: The first loop uses var, which has function scope, so all functions in the first half of the array close over the same i, which is 3 by the end of the loop. The second loop uses let, which has block scope, so each function in the second half closes over a different j value (0, 1, 2), resulting in the output: 3, 3, 3, 0, 1, 2.

Solution Q7:

The correct answer is D.

Explanation:

  • The event starts at the top (document root) and moves down to the target element during the capture phase, triggering capture listeners (Outer Capture, Middle Capture, Inner Capture).
  • Once it reaches the target (inner button), it triggers the target’s listeners in order of registration (Inner Capture, then Inner Bubble).
  • Then it bubbles up, triggering bubble listeners on each ancestor (Middle Bubble, Outer Bubble).

This example demonstrates a full lifecycle of an event. You can stop the propagation by calling stopImmediatePropagation or stopPropagation function.

Top comments (6)

Collapse
 
oculus42 profile image
Samuel Rouse • Edited

Solution Q1 is incorrect: The answer is not B.

getStatus attempts to call this.getName() which is not a function and produces TypeError: this.getName is not a function

I loaded your code into RunJS to verify this.

Collapse
 
lorenzhw profile image
Lorenz Hofmann-Wellenhof • Edited

@oculus42 hups.. I fcked up. Thanks for catching this!! I could have sworn I tested everything before I published. But maybe I made some last-minute changes which I didn't test properly....

Anyways.. I updated the post and gave you credit.

Thanks again!

Collapse
 
oculus42 profile image
Samuel Rouse

Be aware the error message in Solution Q5 varies based on the JavaScript Engine. I'm not sure what you used, though, because your error doesn't match any of mine:

  • Chrome, Edge, Arc: Uncaught TypeError: Cannot read properties of null (reading 'name')
  • Firefox: Uncaught TypeError: null has no properties
  • Safari: TypeError: Right side of assignment cannot be destructured
Collapse
 
lorenzhw profile image
Lorenz Hofmann-Wellenhof • Edited

Thanks @oculus42. I also updated the solution. I only tested in Brave (Chromium)

Collapse
 
manchicken profile image
Mike Stemle

This was fun. Thanks.

Collapse
 
lorenzhw profile image
Lorenz Hofmann-Wellenhof

Thanks Mike :)