Skip to content

Instantly share code, notes, and snippets.

@traviskaufman
Last active November 1, 2016 20:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save traviskaufman/5281661 to your computer and use it in GitHub Desktop.
Save traviskaufman/5281661 to your computer and use it in GitHub Desktop.
Comprehensive Front-End Technical Interview Question

###Comprehensive Technical Interview Question

Consider the following javascript module:

/**
 * A module for tracking when a user visits the page.
 */
window.VisitingDateTracker = {
  /**
   * Initialize the tracker.
   */
  init: function() {
    this._visitTimestamp = new Date();
  },

  /**
   * We don't want clients modifying the original _visitTimestamp, so they can
   * use this method to retrieve it.
   */
  getVisitTimestamp: function() {
    return this._visitTimestamp;
  },

  /**
   * @private
   */
  _visitTimestamp: null
};

// IE8 Madness
if (typeof window.addEventListener === "function") {
  window.addEventListener('load', VisitingDateTracker.init, false);
} else { // IE8
  window.attachEvent('load', VisitingDateTracker.init);
}

We wish to capture the date/time when a user immediately entered our page so we can use it for analytics purposes (or come up with some other user story).

Q1-1: Will this code work as expected?

A1-1: No. If s/he answers "yes", ask why they think it will work, and try and point out the place where they go wrong. If they answer correctly, ask...

Q1-2: Why won't it work as expected?

A1-2: VisitingDateTracker.init's receiver will be bound to the Global object (aka the window object for browsers), which means that when init tries to set this._visitTimestamp it will set that property on window instead of VisitingDateTracker.

Q1-3: How could you modify the code to make it behave as expected?

A1-3: Two ways:

  • The naive way: modify the callback for window.addEventListener
window.addEventListener('load', function() { VisitingDateTracker.init() }, false);
  • The robust way: Bind init's receiver to VisitingDateTracker. Inside the VisitingDateTracker Code:
init: (function() {/* ... */}).bind(this),
// ....

The ideal candidate would know (and tell you about) both ways. If s/he doesn't do it both ways ask if there's another way to do it without modifying either VisitingDateTracker or addEventListener, depending on how they did it. Also if they happen to use bind, ask them if their code would work in IE8, or some other older browser (that doesn't support ES5). The correct answer to this is "no", and then ask him/her to write their own (basic) version of it. Something like:

var _bind = function(fn, ctx) {
  return function() {
    return fn.apply(ctx, Array.prototype.slice.call(arguments));
  };
};

Points off for trying to extend the native function object and/or not passing through the arguments to the bound function. Bonus points for implementing partial composition.

As you can see you can go pretty crazy with this question.

Q2: Let's say we want to modify init so that it can be called no more than one time, this way we can ensure that clients don't try and stupidly call init multiple times and skew the actual visiting timestamp for the user. Could you modify this code so that it will only execute the first time it is invoked?

A2: Something like

// inside VisitingDateTracker
init: (function() {
  var hasBeenCalled = false;
  return function {
    if (hasBeenCalled) {
      return;
    }
    
    hasBeenCalled = true;
    // original init code goes here
  };
})(),

// ....

If the candidate does this, as a follow up you can ask him/her to refactor that logic into some function (i.e. once) that will execute an arbitrary function just one time.

var once = function(fn) {
  var hasBeenCalled = false;
  return function() {
    if (hasBeenCalled) {
      return;
    }
    
    hasBeenCalled = true;
    return fn.apply(this, Array.prototype.slice.call(arguments));
  };
};

Points off for not returning the result of fn.apply and/or not passing in arguments to fn.

Q2-BONUS: Let's say you were writing this in a language other than Javascript, i.e. Python, Java, or C++. What other consideration for once would you have to take into affect? (Good question for full-stack candidates/techncial leads, or just to test the candidate's knowledge of systems design)

A2-BONUS: The one that comes to my mind is concurrency. Two simultaneously-executing pieces of code could possibly invoke the one-time function at the "same time", and the second piece of code could invoke the function before the first piece of code sets hasBeenCalled to true. Thankfully in JS-land where everything is single-threaded we don't have to worry about this :) Solution to this problem: synchronize the critical region of this function using a mutex/semaphore.

Other problems the candidate may mention could be return types (in statically-typed languages) and variadic arguments.

Q3 (open-ended): Can you think of any ways to make this code more robust?

A3: Any of the following, including but not limited to:

  • Wrap the code in an immediately-invoked function expression ((function() { /* code goes here.. */ })())
  • Pass in the window object as a closure to the IIFE ((function(w) { /* ... */ })(window))
  • Make sure window is defined before binding to it
  • Etc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment