Answering FEE Interview Questions - Part 4: JS (el repo está muerto)

Taken on a dirt road, somewhere in the northern valley of California, near Redding
Taken on a dirt road, somewhere in the northern valley of California, near Redding

Previously: part 4 - js #2part 4 - js #3

It’s not really muerto, it’s just that I’m finally done going through all the Front-end Interview JS Questions! I will continue to write more stuff for more complex sample questions that I’ve stumbled upon, or just talking about the Flyers or something cool I learned.

Q. What language constructions do you use for iterating over object properties and array items?
Object properties:
  • for...in along with .hasOwnProperty() to make sure we're not looking at the prototype
  • Object.keys({}).forEach(function(key) {}). It works similar to above, but removes the .hasOwnProperty() check.
  • Even better than using .forEach() with .keys() is to do a for loop over the keys array:

    1
    2
    3
    4
    
    var keys = Object.keys(obj);
    for ( var i = 0, l = keys.length; i < l; i++ ) {
      console.log( obj[ keys[ i ] ] );
    }
    jsperf shows this to be quite a bit faster than other iteration methods.
Iterating arrays
  • The ever-trusty for (var x = 0; x < arr.length; x++ >) {} loop
  • arr.forEach(function(val) {})

There are other methods for working with arrays, particularly when you want to produce new arrays, but these are the two ways I typically iterate. There's a good collection of iteration tests on jsperf, which surprisingly shows a while loop being much faster than other methods.

Q. Explain the difference between mutable and immutable objects. What is an example of an immutable object in JavaScript? What are the pros and cons of immutability? How can you achieve immutability in your own code?

I had to do a bit more reading on this question. Inherently, I know that mutability just means that we can change its properties. We can create an object var obj = { prop1 : true };, and later modify that object, obj.prop1 = false; obj.prop2 = true;. If we state that var obj2 = obj;, then any modifications to either obj or obj2 will still yield the same result of obj === obj2; // true.

Immutability is a little stranger to grasp. In JS, strings and numbers are immutable. All string and number operations return a new instance rather than modifying the original. 2 + 3 yields a new number rather than modifying the meaning or value of 2.

Objects can be made immutable in JS through developer discipline, and significantly helped through the use of a library like Immutable.js. The basic gist is that any modification to an existing object yields a new object. The developer must stop using dot notation to mutate an object, and instead uses setter functions.

The main benefit of immutability is the ability to check if the state of an object has changed. This is great for libraries like React. The components on a page don't necessarily need to know what changed in an object's state, they just need to know that an object has changed, so it can then re-render. A component no longer needs to do a potentially-deep value check on an object. It can just look and see that newState !== oldState quickly and easily.

The major downside to using immutable objects in JS is that it's a pretty foreign concept for most JS developers. It requires a developer and any team of developers to stop accessing an object's properties through traditional methods, and instead rely exclusively on mutation methods that always return a new object.

Q. Explain the difference between synchronous and asynchronous functions.
Synchronous functions

This is how functions have always worked in JS. They are executed line-by-line, with each subsequent line waiting for the previous to finish.

Asynchronous functions

JS has had some async operations for some time now, most notably the XMLHttpRequest object, which would spawn an HTTP request in a non-blocking manner, and then later execute some callback on the returned data. But async functions are a relatively new thing. They allow you to write functions with promises as if they were synchronous functions, which for me at least, makes promise-based code much easier to read and understand.

Here is a quick example, taken from a great primer I read:

Logging a fetch in promise-land
1
2
3
4
5
6
7
8
9
function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}
Logging a fetch in async-land
1
2
3
4
5
6
7
8
9
async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}
Q. What is event loop? What is the difference between call stack and task queue?

The event loop is the term used to describe how JS listens for and processes events that have callbacks registered. In a nutshell, JS will loop, waiting for an event to fire (e.g., click, submit). Once it fires, it looks for callbacks attached and adds them to the task queue where it will be processed in the order it was received. If there is no callback, the event is ignored and the engine continues to listen.

The queue is a list of messages to be processed. As the call stack becomes available, a new stack frame is created and the function associated with the message is added. The function is unpacked and any subsequent functions within are added to the stack.

Q. Explain the differences on the usage of foo between function foo() {} and var foo = function() {}
function foo() {}

This is a function declaration, creating a named function.

var foo = function() {}

This is a function expression, assigning an anonymous function to the variable called foo.

The major difference between the two statements is the way the JS engine interprets the code by separating the variable declaration and assignment via hoisting:

1
2
3
var foo;
// some other variable declarations might be here
foo = function() {};

Now if the function assigned to foo returns a value that we need to initialize another variable, we could encounter errors (the try...catch is just so the script continues):

1
2
3
4
5
6
7
8
9
try {
  var baz = xxx(), // Works because the function declaration is hoisted
      bar = foo(), // whoops
      foo = function() { return false; };
} catch(e) {
  console.log(e); // TypeError: foo is not a function
}
function xxx() { return true; }
console.log( bar, foo, baz ); // undefined undefined true
Q. What are the differences between variables created using let, var or const?
var

I'll start on what I'm most familiar with. var will declare a variable in the scope of the function in which it's contained, or in the window scope if there is no containing function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var x = 1; // window.x
function blurt() {
  // local only to this function
  var x = 2;
  console.log( x );
}

(function() {
  // local only to this IIFE
  var x = 3,
      y = 4;
  console.log( x, y );
})();

blurt();
console.log( x );
console.log( y );
// outputs: 3 4 2 1 reference error (y has not been declared)
const

const is relatively new, and I had never used it in my professional days. It is used to define an identifier (variable would be the wrong term here since variable means its value is unknown or could change) within a block that can not be reassigned. That phrase is a little tricky because you can do some silly things with it:

1
2
3
4
5
6
7
8
9
10
11
const blurt = {},
      hork  = blurt,
      pie   = Math.PI;

blurt.x = 'hi';
hork.y = 'hello';
blurt.z = 'good evening';
blurt === hork; // true
hork = {}; // TypeError: Assignment to constant variable.
pie === Math.PI; // true
pie = 'Delicious; // TypeError: Assignment to constant variable.

As you see, you can modify an object that's assigned to a const. This is where JS' object mutability makes things a little weird.

let

This is another statement that's new to me. let declares a variable with block scope, which means anything within curly braces. Variables declared with let and const do not get hoisted like those declared with var.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let blurt = 1;
if (blurt === 1) {
  // this will throw an error due to blurt's temporal dead zone!
  //console.log( 'in if: ' + blurt );

  // now there's a new `blurt` with a value of 2
  let blurt = 2;
  console.log( blurt ); // 2

  // and now a 3rd instance of `blurt` local only to this for loop!
  for ( let blurt = 1; blurt < 3; blurt++ ) {
    console.log( 'looping: ' + blurt ); // 1 2
  }
  console.log( 'exiting if: ' + blurt ); // 2
}

console.log( blurt ); // 1
Q. What are the differences between ES6 class and ES5 function constructors?

I've done a bit of reading about the new ES6 classes. Most describe them as syntactic sugar (ugh, another term I hate) for traditional constructors and prototypal inheritance. There are a lot of articles out there though that poo-poo the idea of having a strict class idiom in JS, but I have to say, they sure are a helluva lot easier to understand at a glance (example nabbed from Andy Walpole).

ES5 example:
1
2
3
4
5
6
7
8
9
10
11
12
13
var Rectangle = function(id, x, y, width, height) {
    Shape.call(this, id, x, y);
    this.width = width;
    this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var Circle = function(id, x, y, radius) {
    Shape.call(this, id, x, y);
    this.radius = radius;
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
ES6 example:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Rectangle extends Shape {
    constructor(id, x, y, width, height) {
        super(id, x, y);
        this.width = width;
        this.height = height;
    }
}
class Circle extends Shape {
    constructor(id, x, y, radius) {
        super(id, x, y);
        this.radius = radius;
    }
}

It's the same number of lines, and internally it's doing the same stuff, but the ES6 syntax for me is much easier to read and understand. I don't come from an OOP background and my understanding of JS' prototypal pattern is far from comprehensive, so it's likely a lack of experience that draws me to the ES6 class.

Anyway, some details on class:

  • There's no hoisting for classes -- any instantiation must be done after the class definition
  • No need for 'use strict'. This is ES6, so the engine assumes you want that
  • Class names are pretty much consts and can't be overwritten
  • The constructor() method can call super() to instantiate the superclass that a subclass extends
  • Classes can be extended using the extends keyword
Q. Can you offer a use case for the new arrow => function syntax? How does this new syntax differ from other functions? What advantage is there for using the arrow syntax for a method in a constructor?

Here are some of the differences in arrow function syntax and usage:

  • No more function keyword needed (wow, huge time savings!)
  • It lets you omit parenthesis when you have only one input param, omit curlies and the return statement when you're implicitly returning something (wow, huge time savings!)
  • Can't be used as constructors
  • Have no arguments object
  • It takes its this from the enclosing lexical context

My sarcasm is hopefully obvious, because I generally object to anything that removes punctuation or important symbols from code. They're there because they remove ambiguity, which is a pretty important feature in any code.

The last bullet is great though, and hugely beneficial when composing objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var obj1 = {
  timer: undefined,
  count: 0,
  int: function() {
    // set interval is gonna be all screwed up because its
    // `this` is really pointing to the global object (`window`)
    this.timer = setInterval( function() {
      console.log( this.count++ ); // NaN NaN NaN NaN
      if ( this.count > 5 ) {
        clearInterval( this.timer );
      }
    }, 1000 );
  }
};

var obj2 = {
  timer: undefined,
  count: 0,
  int: function() {
    // fat arrow here takes its `this` from the enclosing
    // object. easy-peasy!
    this.timer = setInterval( () => {
      console.log( this.count++ ); // 0 1 2 3 4 5
      if ( this.count > 5 ) {
        clearInterval( this.timer );
      }
    }, 1000 );
  }
};

obj1.int();
obj2.int();
clearInterval( obj1.timer );

In the above script, obj1's version of .int() will never stop spamming your console because this is referring to the global window object, unlike obj2's version which doesn't bind this and takes it from the object in which the function is defined. This is great because it doesn't require an additional call to .bind() (in fact you can't use .bind(), .call(), or .apply() to change the value of this), or creating a closure like var self = this in enclosing function .int(). In my opinion this is one of the very cool features of the new syntax.

Q. What is the definition of a higher-order function?

Functions are first-class members in JS, meaning they can be passed as arguments, returned from other functions (or even overwriting themselves), assigned as a property to an object, or assigned to variables. The first two qualities listed there are what define a higher-order function. In addition to those we've all probably written ourselves without knowing what they're called, there are many available in JS already (e.g. Array.prototype functions .reduce(), .filter(), or .map()).

Q. Can you give an example for destructuring an object or an array?

I just learned about this while reading about higher-order functions. It's a way of extracting (potentially multiple) values from objects and arrays. Here are some simple examples:

1
2
3
4
5
6
7
8
9
10
var [ first, second ] = [ 1, 2, 3, 4, 5 ];
console.log( first, second ); // 1 2
var { first: fname, last: lname } = { first: 'tim', last: 'lynn' };
console.log( fname, lname ); // tim lynn

var arr = [ 1, 2, 3, 4, 5 ];
// same as `length = arr.length`
for (let x = 0, { length } = arr; x < length; x++ ) {
  console.log( arr[ x ] );
}
Q. Can you give an example of a curry function and why this syntax offers an advantage?

Curried functions allow you to write generic functions with varying parameter requirements and either get a result, or a new function with partially-applied parameters. (code samples below snagged from a concise writeup at Carbon Five):

1
2
3
4
5
6
7
8
function add2dumbNums( x ) {
  return function( y ) {
    return x + y;
  }
}
var add20 = add2dumbNums( 20 );
add20( 20 ); // 40
add20( -20 ); // 0

This is a pretty bad example because it requires hard-wiring nested functions for each of the expected params. A better way to do this is to use a currying function which will look at the provided parameters and either execute the function with all the required parameters, or return a curried function to which you can pass additional params to fulfill its expectations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function curry(fx) {
  var arity = fx.length;

  return function f1() {
    var args = Array.prototype.slice.call( arguments, 0 );
    if ( args.length >= arity ) {
      return fx.apply( null, args );
    }
    else {
      return function f2() {
        var args2 = Array.prototype.slice.call( arguments, 0 );
        return f1.apply( null, args.concat( args2 ) );
      }
    }
  };
}

var add4nums = curry( ( a, b, c, d ) => a + b + c + d );
// creates a function that will add 10 to 3 additional nums
var add10 = add4nums( 10 );
// creates a function that will subtract 10 from the sum of 3 additional nums
var sub10 = add4nums( -10 );

I think I’ll finish up this stupidly-long post here. There are a couple more questions in the repo that I’ve omitted in the interest of not boring you (and not feeling like a complete knob because I can’t write a good explanation for it).

Posted under: JS