Categories
JavaScript Basics

Using the Destructuring Assignment Syntax in JavaScript

The destructuring assignment syntax is a JavaScript syntax feature that was introduced in the 2015 version of JavaScript and lets us unpack a list of values of an array or key-value pairs of an object into individual variables.

It’s very handy for retrieving entries from arrays or objects and setting them as values of individual variables. This is very handy because the alternative was to get an entry from an array from an index and then setting them as values of variables for arrays.

For objects, we have the value from the key and set them as values of variables.


Array Destructuring

We can use the destructuring assignment syntax easily in our code. For arrays, we can write:

const [a,b] = [1,2];

Then, we get 1 as the value of a and 2 as the value of b because the destructing syntax unpacked the entries of an array into individual variables.

Note that the number of items in the array does not have to equal the number of variables. For example, we can write:

const [a,b] = [1,2,3]

Then a is still 1 and b is still 2 because the syntax only sets the variables that are listed in the same order as the numbers appeared in the array. So, 1 is set to a, 2 is set to b, and 3 is ignored.

We can also use the rest operator to get the remaining variables that weren’t set to variables. For example, we can have:

const [a,b,...rest] = [1,2,3,4,5,6]

Then, rest would be [3,4,5,6] while we have a set to 1 and b set to 2. This lets us get the remaining array entries into a variable without setting them all to their own variables.

We can use the destructuring assignment syntax for objects as well. For example, we can write:

const {a,b} = {a:1, b:2};

In the code above, a is set to 1 and b is set to 2 as the key is matched to the name of the variable when assigning the values to variables.

Because we have a as the key and 1 as the corresponding value, the variable a is set to 1 as the key name matches the variable name. It is the same with b. We have a key named b with a value of 2, because we have the variable named b, we can set b to 2.

We can declare variables before assigning them with values with the destructuring assignment syntax. For example, we can write:

let a, b;
([a, b] = [1, 2]);

Then, we have a set to 1 and b set to 2 because a and b that were declared are the same ones that are assigned.

As long as the variable names are the same, the JavaScript interpreter is smart enough to do the assignment regardless of whether they’re declared beforehand or not.

We need the parentheses on the line so that the assignment will be interpreted as one line and not individual blocks with an equal sign in between, because two blocks on the same line aren’t valid syntax.

This is only required when the variable declarations happen before the destructuring assignment is made.

We can also set default values for destructuring assignments. For instance:

let a,b;
([a=1,b=2] = [0])

This is valid syntax. In the code above, we get that a is 0 because we assigned 0 to it. b is 2 because we didn’t assign anything to it.

The destructuring assignment syntax can also be used for swapping variables, so we can write:

let a = 1;
let b = 2;
([a,b] = [b,a])

b would become 1 and a would become 2 after the last line of the code above. We no longer have to assign things to temporary variables to swap them, and we also don’t have to add or subtract things to assign variables.

The destructuring assignment syntax also works for assigning returned values of a function to variables.

So, if a function returns an array or object, we can assign them to variables with the destructuring assignment syntax. For example, if we have:

const fn = () =>[1,2]

We can write:

const [a,b] = fn();

To get 1 as a and 2 as b with the destructuring syntax because the returned array is assigned to variables with the syntax.

Similarly, for objects, we can write:

const fn = () => {a:1, b:2}
const {a,b} = fn();

We can ignore variables in the middle by skipping the variable name in the middle of the destructuring assignment. For example, we can write:

const fn = () => [1,2,3];
let [a,,b] = fn();

We get a with the value of 1 and b with the value of 3, skipping the middle value.

It’s important to know that if we use the rest operator with a destructuring assignment syntax, we cannot have a trailing comma on the left side, so this:

let [a, ...b,] = [1, 2, 3];

Will result in a SyntaxError.


Object Destructuring

We can use the destructuring assignment syntax for objects as well. For example, we can write:

const {a,b} = {a:1, b:2};

In the code above, a is set to 1 and b is set to 2 because the key is matched to the name of the variable when assigning the values to variables.

As we have a as the key and 1 as the corresponding value, the variable a is set to 1 because the key name matches the variable name. It is the same with b. We have a key named b with a value of 2, because we have the variable named b, we can set b to 2.

We can also assign it to different variable names, so we don’t have to set the key-value entries to different variable names. We just have to add the name of the variable we want on the value part of the object on the left side, which is the one we want to assign it to, like the following:

const {a: foo, b: bar} = {a:1, b:2};

In the code above, we assigned the value of the key a to foo and the value of the key b to the variable bar. We still need a and b as the keys on the left side so they can be matched to the same key names on the right side for the destructuring assignment.

However, a and b aren’t actually defined as variables. It’s just used to match the key-value pairs on the right side so that they can be set to variables foo and bar.

Destructuring assignments with objects can also have default values. For example, we can write:

let {a = 1, b = 2} = {a: 3};

Then, we have a set to 3 and b set to 2 which is the default value as we didn’t have a key-value pair with a key named b on the right side.

Default values can also be provided if we use the destructuring syntax to assign values to variables that are named differently from the keys of the originating object. So, we can write:

const {a: foo=3, b: bar=4} = {a:1};

In this case, foo would be 1 and bar would be 4 because we assigned the left bar with the default value, but assigned foo to 1 with the destructuring assignment.

The destructuring assignment also works with nested objects. For example, if we have the following object:

let user = {
  id: 42,
  userName: 'dsmith',
  name: {
    firstName: 'Dave',
    lastName: 'Smith'
  }
};

We can write:

let `{`userName`,` name`: { firstName }} =` user;

To set displayName to 'dsmith' , and firstName to 'Dave'. The lookup is done for the whole object and, so, if the structure of the left object is the same as the right object and the keys exist, the destructuring assignment syntax will work.

We can also use the syntax for unpacking values into individual variables while passing objects in as arguments.

To do this, we put what we want to assign the values, which is the stuff that’s on the left side of the destructuring assignment expression, as the parameter of the function.

So, if we want to destructure user into its parts as variables, we can write a function like the following:

const who = (`{`userName`,` name``: { firstName }}) => `${``userName`}'s first name is ${firstName}`;

who(user)

So, we get userName and firstName, which will be set as 'dsmith' and 'Dave' respectively as we applied the destructuring assignment syntax to the argument of the who function, which is the user object we defined before.

Likewise, we can set default parameters as with destructuring in parameters like we did with regular assignment expressions. So, we can write:

const who = (`{`userName = 'djones'`,` name``: { firstName }}) => `${``userName`}'s first name is ${firstName}``

If we have user set to:

let user = {
  id: 42,
  name: {
    firstName: 'Dave',
    lastName: 'Smith'
  }
};

Then we when call who(user), we get 'djones's first name is Dave' as we set 'djones' as the default value for userName.

We can use the destructuring assignment syntax when we are iterating through iterable objects. For example, we can write:

const people = [{
    firstName: 'Dave',
    lastName: 'Smith'
  },
  {
    firstName: 'Jane',
    lastName: 'Smith'
  },
  {
    firstName: 'Don',
    lastName: 'Smith'
  },
]

for (let {
    firstName,
    lastName
  } of people) {
  console.log(firstName, lastName);
}

We get:

Dave Smith
Jane Smith
Don Smith

Logged, as the destructuring syntax works in for...of loops because the variable after the let is the entry of the array.

Computed object properties can also be on the left side of the destructuring assignment expressions. So, we can have something like:

let key = 'a';
let {[key]: bar} = {a: 1};

This will set bar to 1 because [key] is set to a and then the JavaScript interpreter can match the keys on both sides and do the destructuring assignment to the variable bar.

This also means that the key on the left side does not have to be a valid property or variable name. However, the variable name after the colon on the left side has to be a valid property or variable name.

For instance, we can write:

`const obj = { 'abc 123': 1};
const { 'abc 123': abc123 } = obj;

console.log(abc123); //` 1

As long as the key name is the same on both sides, we can have any key in a string to do a destructuring assignment to variables.

Another thing to note is that the destructuring assignment is smart enough to look for the keys on the same level of the prototype chain, so if we have:

var obj = {a: 1};
obj.__proto__.b = 2;
const {a, b} = obj;

We still get a set to 1 and b set to 2 as the JavaScript interpreter looks for b in the prototype inheritance chain and sets the values given by the key b.

As we can see, the destructuring assignment is a very powerful syntax. It saves lots of time writing code to assign array entries to variables or object values into their own variables.

It also lets us swap variables without temporary variables and makes the code much simpler and less confusing. It also works through inheritance so the property does not have to be in the object itself, but works even if the property is in its prototypes.

const fn = () => {a:1, b:2}
const {a,b} = fn();
Categories
JavaScript Interview Questions

JavaScript Interview Questions — Tricky Questions

To get a job as a front end developer, we need to nail the coding interview.

In this article, we’ll look at various kinds of questions that may throw anyone off.

Accidental Global Variable Creation

What are the values that are logged in the console log in the code snippet below?

function foo() {
  let a = b = 0;
  a++;
  return a;
}

foo();

console.log(typeof a);
console.log(typeof b);

typeof a should return 'undefined' so the first console.log is 'undefined' .

However, the second console.log logs 'number' since b is a global variable.

Don’t let the let keyword fool us, b is still a global variable since it has no keyword before it.

b = 0 is the same as window.b = 0 .

To avoid this tricky situation, use strict mode by adding 'use strict' to the top of out code. Then we’ll get the error ‘b is not defined’.

Modules always use strict mode so this is not an issue with them.

Array Length Property

What does the console log on the last line display in the code below?

const fruits = ['apple', 'orange'];
fruits.length = 0;

fruits[0];
console.log(fruits[0])

The console.log should show undefined since we set the fruits ‘s length property to 0, which empties the array.

Therefore, fruits becomes an empty array set setting its length to 0.

Then we display undefined .

Tricky Numbers Array

What does the console log in the code snippet below log?

const length = 4;
const numbers = [];
for (var i = 0; i < length; i++); {
  numbers.push(i + 1);
}

console.log(numbers);

The numbers array should be [5] since i is incremented without running anything since we have:

for (var i = 0; i < length; i++);

and then we have:

{
  numbers.push(i + 1);
}

So we have a for loop that did nothing but increment i and a block that pushes i + 1 to numbers .

The var keyword makes i available outside the for loop. Therefore, we can push i + 1 , which is 5, since i is 4.

Therefore, numbers is [5] .

If we replace var with let , then we won’t have this issue since we’ll get an error when we push as i won’t be available outside the for loop.

Automatic Semicolon Insertion

What does the console log on the last line display?

function foo(item) {
  return
    [item];
}

console.log(foo(5));

It should display undefined since we ran return with nothing returned since a semicolon is automatically inserted on the last line in JavaScript.

[item] is therefore never ran.

To make sure that we don’t make this mistake, we should put whatever we return on the same line as the return keyword.

Tricky Closure

What does the following code display in the console?

let i;
for (i = 0; i < 5; i++) {
  const log = () => {
    console.log(i);
  }
  setTimeout(log, 100);
}

The code above should log 5 five times since setTimeout runs the log function after the for loop is done.

setTimeout is async, so it’s queued in the event loop and runs when all the synchronous code is done running.

Therefore, first the for loop runs and creates a new log function, which captures the variable i .

Then the setTimeout schedules it to be run after the for loop is done.

Then the log function runs after the loop is done when i is 5.

After 100 milliseconds, the 5scheduled log callbacks are called by setTimeout .

log reads the current value of i , which is 5 and runs log with that value.

We can fix this by passing in i to log so that the value of i that’s currently being loop through is preserved in log as follows:

let i;
for (i = 0; i < 5; i++) {
  const log = (i) => {
    console.log(i);
  }
  setTimeout(log, 100, i);
}

All arguments after the 2nd argument are passed into setTimeout are passed into the callback and are accessible via the parameters.

Conclusion

We should be aware of accidentally creating global variables in scripts. Any variables that don’t have a keyword before it is a global variable.

Also, we can create loops that have no blocks below it in JavaScript, so should be careful of not to insert a semicolon between the closing parentheses and the opening curly brackets.

When we want to return a value, we should put whatever it is right after the return keyword.

Finally, if we want a value inside a setTimeout callback when setTimeout is called inside a loop, then we should pass it into the callback so the current loop value is preserved.

Categories
JavaScript Interview Questions

Basic JavaScript Interview Exercises — Numbers and Elements

To get a job as a front end developer, we need to nail the coding interview.

In this article, we’ll look at some quick warmup questions that everyone should know.

Write a function that computes the Fibonacci number of N.

We can do that with a loop and the destructuring syntax of JavaScript.

We create the fib function as follows:

const fib = (n) => {
  let i = 1,
    a = 1,
    b = 1;
  while (i < n) {
    [a, b] = [b, a + b];
    i++;
  }
  return a;
}

In the code above, we set b to a and b to a + b to update the numbers with the new Fibonacci values as we increase i .

Then we return a when we’re done with the loop.

Write a function that accepts a string and returns a map with the strings character frequency.

We can use a JavaScript Map to do this.

We count the frequencies of the characters in a string by splitting it into an array of characters and then counting the frequency of the characters as follows:

const count = str => {
  const chars = str.split('');
  const frequencies = new Map();
  for (let c of chars) {
    const freq = frequencies.get(c) || 0;
    frequencies.set(c, freq + 1);
  }
  return frequencies;
}

In the code, we used the Map ‘s get method to get the frequency, and we add it by 1 and then set it.

Once we’re done with the loop, we return the Map .

Write a function that accepts a number and checks if it’s a prime or not.

We can check if a number is a prime by checking if it’s 2 or odd. If it’s odd, then we try to divide numbers up to the floor of the given number divided by 2.

For example, we can write the following function to check for prime numbers:

const isPrime = (num) => {
  if (num % 2 === 0 && num !== 2) {
    return false;
  }
  for (let i = 3; i <= Math.ceil(num / 2); i++) {
    if (num % i === 0) {
      return false;
    }
  }
  return true
}

We check if it’s even and it’s not 2. If it is, we return false .

Otherwise, we run the loop to check if a number is divisible by 3 up to the ceiling of the num divided 2.

If it’s evenly divisible by any of those, then we return false .

Otherwise, we return true .

Write a function that accepts a DOM element and a string and prints any of its immediate children that contain the class name with that string.

We can use the getElementsByClassName method of an element object to get the children with the given class attribute.

For instance, we can write the following function:

const getChildrenWithClass = (el, className) => {
 const children = el.getElementsByClassName(className);
  for (let c of children) {
   console.log(c);
  }
}

The code above calls the getElementsByClassName on the el element object and prints out the child elements with the given class name.

Also, we can use the querySelectorAll method to do the same thing.

We can write the following:

const getChildrenWithClass = (el, className) => {
  const children = el.querySelectorAll(`.${className}`);
  for (let c of children) {
    console.log(c);
  }
}

The only difference is that we called querySelectAll with the template string `.${className}` .

Write a function that accepts a DOM element and a string and prints if any of its parent nodes contain the class with that string. It should stop when there are no parent elements.

We can use the parentNode property recursively until we reach the root element or until we find the element with the className that we wanted.

To do this, we create a getParentWithClassName as follows:

const getParentWithClassName = (el, className) => {
  let currentEl = el.parentNode;
  while (currentEl) {
    if (currentEl.className === className) {
      return currentEl;
    }
    currentEl = currentEl.parentNode;
  }
  return undefined;
}

In the code above, we set currentEl to the parentNode of el .

Then we use a while loop through to search for a parentNode with the given className until we find one with the given name.

If we find one with the given className , we return the element.

Otherwise, we keep going by setting currrentel to currentEl.parentNode .

If we loop up to the root node and still didn’t find an element with the given className , we return undefined .

Conclusion

We use the parentNode property to find the parent of a child node.

To get the child node with the given CSS selector, we can call any DOM navigation methods to find the elements with the given selector.

To create a dictionary we can use the Map constructor.

We can use the destructuring syntax to reassign multiple things easily as we did with the Fibonacci numbers.

Categories
JavaScript Interview Questions

Basic JavaScript Interview Exercises

To get a job as a front end developer, we need to nail the coding interview.

In this article, we’ll look at some quick warmup questions that everyone should know.

Write a function the reverses a string

We can use JavaScript’s string and array methods to reverse a string easily.

To do this, we can write the following function:

const reverseString = (str) => str.split('').reverse().join('');

The function works by splitting the string into an array of characters, then reversing the array, and joining it back together.

We used JavaScript string’s split method and array’s reverse and join methods.

Write a function that filters out numbers from a list.

We can do that with the isNaN function and the array’s filter method.

To solve this problem, we can write the following code:

const removeNums = (arr) => arr.filter(a => isNaN(+a));

In the removeNums function, we pass in an array arr then call filter on it with a callback that returns isNaN(+a) , which is true if an item is converted to NaN when we try to convert it to a number.

Write a function that finds an element inside an unsorted list.

We can use the array’s findIndex method to find an element inside an unsorted list.

We write the following function:

const search = (arr, searchItem) => arr.findIndex(a => a === searchItem);

to do the search. The findIndex method returns the index of the first item that it finds that meets the condition in the callback.

We can use it as follows:

console.log(search(['foo', 'bar', 1], 'foo'));

to search for the string 'foo' . We then should get 0 since 'foo' is the first entry in the array.

Write a function that showcases the usage of closures.

A closure is a function that returns a function. It’s usually used to hide some data inside the outer function to keep them from being exposed from the outside.

We can do that by writing:

const multiply = (first) => {
  let a = first;
  return (b) => {
    return a * b;
  };
}

Then we can call it by writing:

console.log(multiply(2)(3));

which gets us 6.

What is a Promise? Write a function that returns a Promise.

A promise is a piece of asynchronous code that runs in an indeterminate amount of time.

It can have the pending, fulfilled or rejected states. Fulfilled means it’s successful, rejected means that it failed.

An example of a promise is the Fetch API. It returns a promise and we can use it to return a promise ourselves.

For instance, we can write:

const getJoke = async () => {
  const res = await fetch('http://api.icndb.com/jokes/random')
  const joke = await res.json();
  return joke;
}

to get a joke from the Chuck Norris API.

Write a function that flattens a list of items.

We can use the array flat method to flatten a an array of items.

For example, we can write:

const flatten = arr => arr.flat(Infinity);

to flatten all levels of an array to one level.

We can also loop through each item of an array and recusively flatten nested arrays into one level.

For instance, we can write the following:

const flatten = (arr = []) => {
  let result = [];
  for (let item of arr) {
    if (Array.isArray(item)) {
      result = result.concat(flatten(item));
    } else {
      result = result.concat(item);
    }
  }
  return result;
}

to flatten the array.

The code works by looping through each entry of the array. Then find the arrays in the entries and the flatten calls itself then append it to result. Otherwise, it just adds the item into the result array.

After it went through all the levels, it returns result .

Write a function that accepts two numbers **a** and **b** and returns both the division of **a** and **b** and their modulo of **a** and**b**.

We can do that by using the / operator to divide a and b , and the % operator to find the remainder when we divide a by b .

To do that, we can write the following function:

const divMod = (a, b) => {
  if (b !== 0) {
    return [a / b, a % b];
  }
  return [0, 0];
}

We check if the divisor is zero, then we do the operations as we mentioned and return the computed items in an array.

Conclusion

We can use arrays and string methods as much as possible to make our lives easier.

They’re also more efficient than what we implement from scratch.

Categories
JavaScript Interview Questions

JavaScript Interview Questions — DOM and Event Questions

To get a job as a front end developer, we need to nail the coding interview.

In this article, we’ll look at some harder questions about DOM manipulation and handling events.

What is a repaint and when does this happen?

A repaint happens when we change the look of an element without changing its size and shape.

It doesn’t cause reflow since its dimensions and position didn’t change.

The repainting process happens when an element changes the background color, change text color, or hide visibility.

How could we run some JavaScript when DOM is ready like $(document).ready?

We can put our scripts in the HTML body element. The DOM would be ready by the time the browser runs the script tag there.

Also, we can put our code inside the DOMContentLoaded event handler. The code inside will run only when the DOM is completely loaded.

For example, we can write the following:

document.addEventListener('DOMContentLoaded', () => {
  console.log('DOM loaded');
});

We can also watch the readystatechange event by attaching a listener to it.

When the readyState is 'complete' , then we know the DOM has loaded.

For instance, we can write the following code to do that:

document.onreadystatechange = () => {
  if (document.readyState == "complete") {
    console.log('DOM loaded');
  }
}

What is event bubbling? How does event flow?

Event bubbling means that the event propagates from the originating element to its parent, grandparent, and all the way up to the window object.

The browser will run all event handlers that are attached to all the parent elements of the originating element in addition to the originating element.

For example, if we have the following HTML:

<div>
  <p>
    <button>Click</button>
  </p>
</div>

Then when we attach event listeners to all the elements and document and window as follows:

const div = document.querySelector('div');
const p = document.querySelector('p');
const button = document.querySelector('button');

button.onclick = () => {
  alert('button clicked');
}

p.onclick = () => {
  alert('p clicked');
}

div.onclick = () => {
  alert('div clicked');
}

document.onclick = () => {
  alert('document clicked');
}

window.onclick = () => {
  alert('window clicked');
}

and click the Click button, then we’ll see all the alerts listed in the same order that we listed in the code.

So we get ‘button clicked’, ‘p clicked’, ‘div clicked’, ‘document clicked’ and ‘window clicked’ alerts displayed in that order.

How would we destroy multiple list items with one click handler?

We can use event delegation to do that.

It works by listening to the clicks of the parent element of the list. Then we can check which child has been clicked in the click handler and then remove that element from the DOM.

For example, if we have the following HTML:

<ul>
    <li>first</li>
    <li>second</li>
    <li>third</li>
    <li>forth</li>
    <li>Fifth</li>
</ul>

Then we can write the following JavaScript code to remove the li elements that we clicked on as follows:

document.querySelector('ul').addEventListener('click', (e) => {
  const elm = e.target.parentNode;
  elm.removeChild(e.target);
  e.preventDefault();
});

In the code above, we get the parentNode property of the element we clicked on to get the ul.

Then we can call removeChild on it to remove the li that we clicked on since e.target is the element that we clicked on, which is the li.

Finally, we call preventDefault to stop event propagation.

Create a button that is destroyed by clicking on it but two new buttons are created in its place.

We can do that by using the logic above for removing the button that we clicked on.

Then we add use createElement and appendChild to create more buttons and add them to the list.

For example, given the following HTML:

<div>
  <button>button</button>
</div>

We write the following JavaScript code to add 2 buttons and then remove the original button that was clicked on by attaching a click listener to the div and then manipulating the buttons:

document.querySelector('div').addEventListener('click', (e) => {
  if (e.target.tagName === 'DIV') {
    return;
  }
  const elm = e.target.parentNode;
  e.preventDefault();

  const btn = document.createElement('button');
  btn.innerHTML = 'button';

  const btn2 = document.createElement('button');
  btn2.innerHTML = 'button';

  elm.appendChild(btn);
  elm.appendChild(btn2);
  elm.removeChild(e.target);
});

In the code above, we check if we actually clicked on a button.

If we did, then we proceed to create 2 buttons. Then we call appendChild on the parentNode of the button that was clicked, which is the div, to attach the 2 buttons.

Then we call removeChild on e.target , which should the button since we checked it’s not a div, to remove the button.

Conclusion

We can watch if the DOM is ready with readystatechange or DOMContentLoaded events.

Event bubbling happens when an element’s events propagate up the DOM tree.

appendChild and removeChild are used to add and remove elements. We can handle events of multiple child elements with event delegation.

A repaint happens when we change the look of an element without changing its geometry.