UIZE JavaScript Framework

Javascript Interview Questions

1. Introduction

The interview questions in this document are designed to explore aspects of a candidate's knowledge of, and familiarity with, the JavaScript language.

Some of the questions test whether a person has knowledge of some of the more esoteric facilities in the language, while some just test how a person can think outside the box and utilize their knowledge of the language to fashion solutions within given constraints / requirements. These questions are generally small enough in scope that they can be useful when interviewing candidates for a UI engineering position where strong JavaScript experience is required.

Even if you are not yourself interviewing for a position, or interviewing some other person for a position, you may still enjoy these brain teasers - as long as you have an appreciation for the JavaScript language.

2. Questions

2.1. QUESTION: Aynchronous Processing of Array

Write a function to asynchronously iterate through and process the elements of a specified array.

REQUIREMENTS

Your function should expect two parameters: the first being the array of items to process, and the second being a reference to an external function that should be called in order to process each item.
The external function expects two parameters: the first being an item to process, and the second being a callback function that it will call once it has finished processing the item. The callback is important, because processing the item is asynchronous (e.g. it may involve an AJAX request to a Web service). You don't have to implement the external function, and it's not particularly relevant what it does with each item.
Your implementation must be encapsulated inside a function. You may not write other functions outside of it.
Your implementation must not be destructive to the items array parameter.

COMPLETE

function processItems (items,processItem) {
  // FILL THIS IN
}

See ANSWER: Aynchronous Processing of Array

2.2. QUESTION: Hex to Decimal Conversion

Write a function to accept a string that is a hex format number of any length and convert it to a decimal

COMPLETE

function hexToDecimal (hexStr) {
  // FILL THIS IN
}

See ANSWER: Hex to Decimal Conversion

2.3. QUESTION: Remove Array Values

You have a master array of strings, where each element is a fruit name. You have a second array of fruit name strings, that is a list of fruits that should be removed from the fruits specified in the master array. For the purpose of the exercise, we will call the master array fruits and the second array fruitsToRemove. Write the function that will remove the values contained in fruitsToRemove from the array fruits.

COMPLETE

function removeFruits (fruits,fruitsToRemove) {
  // FILL THIS IN
}

See ANSWER: Remove Array Values

2.4. QUESTION: Check if a String is Only Whitespace

Write a function - whose implementation is only a single statement - that will return true if a specified string consists of only whitespace.

function isOnlyWhitespace (sourceStr) {
  // FILL THIS IN
}

See ANSWER: Check if a String is Only Whitespace

2.5. QUESTION: Push Onto Array

Write a function to push either a simple value or an array of values onto a specified array. For the purpose of the exercise, we will call the target array simply array and the stuff to push onto it (either a simple value or array) simply toPush. If toPush is a simple value, it should be pushed onto array as an element. If toPush is an array, all of its elements should be pushed onto array. Your solution should modify array (i.e. not return a new array).

COMPLETE

function pushOntoArray (array,toPush) {
  // FILL THIS IN
}

See ANSWER: Push Onto Array

2.6. QUESTION: Round a Positive Number

Write a function that will round a positive number - without using any built-in methods of the Math object (so, no Math.round, Math.floor, Math.ceil, etc.).

COMPLETE

function roundPositiveNumber (number) {
  // FILL THIS IN
}

See ANSWER: Round a Positive Number

2.7. QUESTION: Do Stuff If Object Not Empty

Write a function that accepts an object and does some stuff, but only if the object has some properties in it (i.e. it's not an empty object). The "some stuff" is not important and can just be a placeholder comment // do some stuff.

COMPLETE

function myFunction (object) {
  // FILL THIS IN
}

See ANSWER: Do Stuff If Object Not Empty

2.8. QUESTION: Translation in One Statement

Write a function that translates a specified english word to a specified language.

REQUIREMENTS

write a function that translates a specified english word to a specified language
the dictionary contains translation for only the words "hello", "goodbye", and "thank you", for the languages French, Japanese, German, and Italian
the function's implementation must be a single statement
the language name can be specified in lower case, upper case, or mixed case
the English word specified can be in lower case or upper case (or mixed), and leading spaces and trailing spaces should be ignored
if an unrecognized language or word is specified, the function should return an empty string

COMPLETE

function translate (word,language) {
  // FILL THIS IN
}

DICTIONARY

French
  hello = bonjour
  goodbye = au revoir
  thank you = merci

Japanese
  hello = konnichi wa
  goodbye = sayounara
  thank you = arigatou gozaimasu

German
  hello = hallo
  goodbye = auf wiedersehen
  thank you = danke

Italian
  hello = ciao
  goodbye = arrivederci
  thank you = grazie

See ANSWER: Translation in One Statement

2.9. QUESTION: Test For Rectangles Overlapping

Write a function that returns a boolean, indicating whether or not two rectangles overlap.

For the purpose of the exercise, the first rectangle is expressed as aX (left), aY (top), aW (width), and aH (height), and the second rectangle as bX, bY, bW, and bH. All measurements are in pixels.

COMPLETE

function doRectanglesOverlap (aX,aY,aW,aH,bX,bY,bW,bH) {
  // FILL THIS IN
}

See ANSWER: Test For Rectangles Overlapping

2.10. QUESTION: Split List String, Using Comma

Given a string, sourceStr, write some code that will split this string using comma as your delimiter, and producing an empty array if the string is empty.

COMPLETE

function splitListStrUsingComma (sourceStr) {
  // FILL THIS IN
}

See ANSWER: Split List String, Using Comma

3. Answers

3.1. ANSWER: Aynchronous Processing of Array

The first instinct of a candidate might be to use a for loop.

This question is a good test of whether or not a candidate understands the implications of asynchronous coding. A typical first pass attempt will fail because a for loop will immediately spawn a whole bunch of calls to processItem. Upon realizing that a for loop isn't up to the task, the next test for the candidate is whether or not they understand the behavior and implications of closures.

SOLUTION

function processItems (items,processItem) {
  var itemNo = -1;
  (function next () {if (++itemNo < items.length) processItem (items [itemNo],next)}) ();
}

The above solution works because the next function is a closure, and so it gets to keep a discrete state for itemNo that it can use while iterating through the items array. The first thing the next function does when it is called is to do a bounds check to make sure the end of the items array has not been reached. The itemNo variable is initialized to -1 because it will be incremented to 0 in the first call to next, using the prefix increment operator. The next closure is passed as the callback parameter in the call to the processItem asynchronous external function. When the processItem function calls next after an item is finished being processed, the next closure has access to the previous state for the itemNo variable.

What gets the ball rolling and kicks off the asynchronous iteration is the call of next immediately after it is declared, using the form (function blah () {}) (). The parentheses around the function declaration are necessary in order to avoid a syntax error. The result of a function declaration is a reference to the function, so we can call it straight away by appending the ().

FOLLOW-ON QUESTION

What happens if you call processItems again with a different array while it is still busy iterating through an array from a previous call?

3.2. ANSWER: Hex to Decimal Conversion

3.2.1. Solutions Using Iteration

If the candidate doesn't realize there is a built-in facility for converting from hex to decimal, then they might fashion an answer by writing a loop to iterate through the characters of the string. This is fine, and could provide a good opportunity to gauge algorithm skills. Solutions like the following are respectable, if not the most concise.

SOLUTION 1

function hexToDecimal (hexStr) {
  var
    hexToDecMap =
      {0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,b:11,c:12,d:13,e:14,f:15},
    result = 0
  ;
  hexStr = hexStr.toLowercase ();
  for (var charNo = -1; ++charNo < hexStr.length;) {
    result = result << 4 + hexToDecMap [hexStr [charNo]];
  }
  return result;
}

SOLUTION 2

function hexToDecimal (hexStr) {
  var
    hexDigits = '0123456789abcdef',
    result = 0
  ;
  hexStr = hexStr.toLowercase ();
  for (var charNo = -1; ++charNo < hexStr.length;) {
    result = result << 4 + hexDigits.indexOf (hexStr [charNo]);
  }
  return _result;
}

3.2.2. Concise Solutions

function hexToDecimal (hexStr) {
  return parseInt (hexStr,16);
}

In addition to the built-in parseInt function, with its optional base second parameter, the language also has support for hex formatting of numbers, and there are several ways of gaining access to that built in hex format support.

function hexToDecimal (hexStr) {
  return eval ('0x' + hexStr);
}

...or...

function hexToDecimal (hexStr) {
  return new Number ('0x' + hexStr);
}

...or...

function hexToDecimal (hexStr) {
  return +('0x' + hexStr);
}

FOLLOW-ON QUESTION

Which of the above concise solutions would perform the best?

ANSWER

Probably the third one. The first invokes the interpreter to evaluate what could be arbitrary JavaScript code, so there is probably some overhead. The second involves object construction (and, therefore, a function call - albeit a native function). The third approach uses built-in type conversion facilities of the JavaScript language that are likely to perform the best (this has not been tested).

NOTES

if the candidate goes straight to using a concise approach that uses built-in functionality, one might turn the question around the other way and ask how the candidate might write their own conversion algorithm from scratch.

Return to QUESTION: Hex to Decimal Conversion

3.3. ANSWER: Remove Array Values

3.3.1. Part 1

Write code that will return an array that is the master array minus all the fruits specific in the second array.

SOLUTION

function removeFruits (fruits,fruitsToRemove) {
  var
    newFruits = [],
    fruitsToRemoveHash = {}
  ;
  for (var fruitNo = fruitsToRemove.length - 1; fruitNo >= 0; fruitNo--) {
    fruitsToRemoveHash [fruitsToRemove [fruitNo]] = 1;
  }
  for (var fruitNo = -1; ++fruitNo < fruits.length;) {
    var fruit = fruits [fruitNo];
    if (!fruitsToRemoveHash [fruit]) newFruits.push (fruit);
  }
  return newFruits;
}

NOTES

Iterating in reverse does not affect the results of the first loop, but it offers slightly better performance.
While it's not ideal if the candidate implements an O(n^2) solution, if they understand that that is obviously a very inefficient solution and are just doing it to get started, that's okay. An O(n^2) solution would involve iterating through the array of fruits to remove, and for each one iterating through the array of fruits and searching for the element to splice out.

3.3.2. Part 2

Now solve the same problem in just one statement for the function's implementation.

function removeFruits (fruits,fruitsToRemove) {
  return ('<' + fruits.join ('><') + '>').replace (new RegExp ('<' + fruitsToRemove.join ('>|<') + '>','g'),'').replace (/^<|>$/g,'').split ('><');
}

NOTES

The candidate will spend a good deal of futile time wondering if there is just a magical built-in method that will do it for them. This is healthy.
After resigning to the fact that there is no magical method, the candidate will think of how they can use iterators and still have it be just one statement.
It might require nudging to get the candidate to think outside of the realm of iterators and array methods, and not think of the problem as a problem of modifying an array (remember, the problem is not to modify the original array, but to return an array... and remember, there are specific constraints on the nature of the element values).
Eventually the candidate should start thinking along the lines of using or'ed regular expression replacement followed by splitting to create a new array, but the snags along the way involve unsafe approaches that would replace "apple" in "pineapple", or "pear" in "avocado pear" (which is technically a fruit, by the way).

Return to QUESTION: Remove Array Values

3.4. ANSWER: Check if a String is Only Whitespace

3.4.1. Obvious Solution

Using a regular expression...

function isOnlyWhitespace (sourceStr) {
  return sourceStr.search (/\S/) == -1;
}

...or...

function isOnlyWhitespace (sourceStr) {
  return !/\S/.test (sourceStr);
}

...or...

function isOnlyWhitespace (sourceStr) {
  return /^\s*$/.test (sourceStr);
}

3.4.2. The Twist

Now, solve the problem without using a regular expression.

function isOnlyWhitespace (sourceStr) {
  return !isNaN (+(sourceStr + ' 0'));
}

...or...

function isOnlyWhitespace (sourceStr) {
  return _sourceStr + ' 0' == 0;
}

WHY DOES THIS WORK?

According to the language specification, the valid format for a number does not permit spaces between characters, so if prefixing the string ' 0' with the source string adds anything but additional leading whitespace, then the resultant string cannot be a number and one can test on this to conclude whether or not the source string contains only whitespace.

Return to QUESTION: Check if a String is Only Whitespace

3.5. ANSWER: Push Onto Array

3.5.1. Obvious Solution

A candidate may grapple for some time, wondering if there is some built-in way to do it. Then a candidate may wonder how it could be accomplished using methods of the Array object, like concat or splice. The concat method has the downside that it creates a new array as the result. The splice method has the downside that it takes an arbitrary number of optional parameters - being elements to splice in, but toPush is an array.

function pushOntoArray (array,toPush) {
  if (toPush instanceof Array) {
    for (var elementNo = -1; ++elementNo < toPush.length;) {
      array.push (toPush [elementNo]);
    }
  } else {
    array.push (toPush);
  }
}

...or...

function pushOntoArray (array,toPush) {
  if (!(toPush instanceof Array)) toPush = [toPush];
  for (var elementNo = -1; ++elementNo < toPush.length;) {
    array.push (toPush [elementNo]);
  }
}

3.5.2. Efficient Solution

A healthy comprehension of the JavaScript language will lead a candidate to realize that the call and/or apply methods of the Function object could be useful in solving the problem. If not, pose the follow-on question: how could you write the function with just one statement in its implementation?

SOLUTION 1

function pushOntoArray (array,toPush) {
  array.push.apply (array,toPush instanceof Array ? toPush : [toPush]);
}

SOLUTION 2

function pushOntoArray (array,toPush) {
  array.push [toPush instanceof Array ? 'apply' : 'call'] (array,toPush);
}

SOLUTION 3

function pushOntoArray (array,toPush) {
  toPush instanceof Array ? array.push.apply (array,toPush) : array.push (toPush);
}

FOLLOW-ON QUESTION

Discuss the code size and performance differences between the above three solutions.

Return to QUESTION: Push Onto Array

3.6. ANSWER: Round a Positive Number

Rounding has the effect of producing an integer from a potentially floating point number. So, how else could you turn a floating point number to an integer?

function roundPositiveNumber (number) {
  return (number + .5) >> 0;
}

...or...

function roundPositiveNumber (number) {
  return (number + .5) | 0;
}

...or...

function roundPositiveNumber (number) {
  return parseInt (number + .5);
}

...or...

function roundPositiveNumber (number) {
  return +(number + .5).toFixed (0);
}

FOLLOW-ON QUESTION

Which of the above solutions would have the best performance?

ANSWER

Probably the first or second solutions, since they don't involve the overhead of performing any additional function or method calls.

ANOTHER FOLLOW-ON QUESTION

Without using a conditional statement (including ternary operators), build on the first solution to produce a solution that will round both positive and negative numbers.

SOLUTION

function roundNumber (number) {
  return (number | 0) + (number * 2 | 0) % 2;
}

Explain why this works.

Return to QUESTION: Round a Positive Number

3.7. ANSWER: Do Stuff If Object Not Empty

The candidate is likely to follow a typical thought process of 1) determine if the object isn't empty, and 2) if the object isn't empty, then do the stuff. Hopefully the candidate will at least realize to use a for...in loop to determine if the object has contents.

TYPICAL SOLUTION

function myFunction (object) {
  var objectHasProperties = false;
  for (var prop in object) {
    objectHasProperties = true;
    break;
  }
  if (objectHasProperties) {
    // do some stuff
  }
}

CONCISE SOLUTION

function myFunction (_object) {
  for (var prop in object) {
    // do some stuff
    break;
  }
}

With the break statement at the end, and given the behavior of the for...in loop, the loop ends up acting as a conditional block.

Return to QUESTION: Do Stuff If Object Not Empty

3.8. ANSWER: Translation in One Statement

This hypothetical (and very non real world) exercise has the following objectives...

OBJECTIVES

test basic knowledge of JSON syntax
test basic problem solving skills (i.e. arriving at conclusion to use two dimensional "hash tables")
test skills in gathering and digesting/understanding requirements
test comfort level with language model, with the use of immediate indexing into anonymous objects that are constructed as part of a more complex expression
test familiarity with JavaScript's handling of conditionals (using the || operator in defaulting of values)
test basic familiarity with regular expression syntax and some String class methods

SOLUTION

function translate (word,language) {
  return (
    (
      {
        french:{
          hello:'bonjour',
          googbye:'au revoir',
          thankyou:'merci'
        },
        japanese:{
          hello:'konnichi wa',
          googbye:'sayounara',
          thankyou:'arigatou gozaimasu'
        },
        german:{
          hello:'hallo',
          googbye:'auf wiedersehen',
          thankyou:'danke'
        },
        italian:{
          hello:'ciao',
          googbye:'arrivederci',
          thankyou:'grazie'
        }
      } [language.toLowerCase ()] || {}
    ) [word.toLowerCase ().replace (/s/g,'')] || ''
  );
}

Return to QUESTION: Translation in One Statement

3.9. ANSWER: Test For Rectangles Overlapping

Thinking through how to test for overlapping rectangles can easily lead to a massive boolean expression that tests for all the possible permutations of corners of one rectangle falling within the other rectangle.

One way to express this line of thinking is to divide the problem into tests for each of the X- and Y- axes - for each axis testing both ends of the line segments of each rectangle to see if any falls within the line segment of the other rectangle. The result could look something like the following...

TYPICAL SOLUTION

function doRectanglesOverlap (aX,aY,aW,aH,bX,bY,bW,bH) {
  (
    (aX >= bX && aX <= bX + bW - 1) ||
    (aX + aW - 1 >= bX && aX + aW - 1 <= bX + bW - 1) ||
    (bX >= aX && bX <= aX + aW - 1) ||
    (bX + bW - 1 >= aX && bX + bW - 1 <= aX + aW - 1)
  ) &&
  (
    (aY >= bY && aY <= bY + bH - 1) ||
    (aY + aH - 1 >= bY && aY + aH - 1 <= bY + bH - 1) ||
    (bY >= aY && bY <= aY + aH - 1) ||
    (bY + bH - 1 >= aY && bY + bH - 1 <= aY + aH - 1)
  )
}

As long as any end of any line segment falls within the line segment of the other rectangle on both axes, then the rectangles overlap. Problem is, this is a very bloated solution. Thinking about the problem differently leads to a more elegant solution.

CONCISE SOLUTION

function doRectanglesOverlap (aX,aY,aW,aH,bX,bY,bW,bH) {
  return (
    aX + aW - 1 >= bX && bX + bW - 1 >= aX &&
    aY + aH - 1 >= bY && bY + bH - 1 >= aY
  );
}

It's easier to understand this elegant (in its simplicity) solution by approaching it from the inverse...

The segments [x1_lo, x1_hi] and [x2_lo, x2_hi] don't overlap if:

(x1_hi < x2_lo) || (x1_lo > x2_hi)

If x1_hi is less than x2_lo, then clearly the whole segment x1 is outside of segment x2, since x1_lo is lower in value than x1_hi and therefore guaranteed to also be lower in value than x2_lo...

CASE: x1_hi < x2_lo

x1: ....|x1_lo---------x1_hi|.......................
x2: ...........................|x2_lo-------x2_hi|..

Here, x1_hi < x2_lo, so x1_lo < x2_lo as well, and there's no overlap.

CASE: x1_lo > x2_hi

x1: .........................|x1_lo---------x1_hi|..
x2: ....|x2_lo-------x2_hi|.........................

Here, x1_lo > x2_hi, so x1_hi > x2_hi as well, and there's no overlap.

Now, if a segment doesn't not overlap, then it does overlap, so we NOT the expression (that we can easily understand) for the not overlapping case.

In other words, we take...

!overlap = (x1_hi < x2_lo) || (x1_lo > x2_hi)

...and treat is as an equation and NOT both sides, to get...

overlap = !((x1_hi < x2_lo) || (x1_lo > x2_hi))

If we distribute the NOT, using the rules of Boolean logic, we get...

overlap = !(x1_hi < x2_lo) && !(x1_lo > x2_hi)

...which further reduces to...

overlap = (x1_hi >= x2_lo) && (x1_lo <= x2_hi)

...which is the same as...

overlap = (x1_hi >= x2_lo) && (x2_hi >= x1_lo)

Given that our rectangle parameters are aX, aW, bX, and bW, the condition for testing the X-axis becomes...

aX + aW - 1 >= bX && bX + bW - 1 >= aX

Combined with the same test for the Y-axis, we get...

aX + aW - 1 >= bX && bX + bW - 1 >= aX &&
aY + aH - 1 >= bY && bY + bH - 1 >= aY

Short and sweet!

Return to QUESTION: Test For Rectangles Overlapping

3.10. ANSWER: Split List String, Using Comma

Hopefully the candidate will know about the split method of the String object, hopefully they will know its signature, and hopefully they will know that the method always returns an array with at least one element.

Always returning at least one element can be problematic when parsing a list string that was produced by serializing an empty array. Of course, the split method doesn't know that the string doesn't represent a list with one element that is an empty string, but is instead supposed to represent an empty list. However, we might know that our original list array never contains empty string elements. So, we want a function that will give us an empty array for an empty string.

TYPICAL SOLUTION

function splitListStrUsingComma (sourceStr) {
  if (sourceStr == '') {
    return [];
  } else {
    return sourceStr.split (',');
  }
}

A promising candidate will be aware of and comfortable with the ternary conditional operator - it will be a part of their bag of tricks. A promising candidate will also be aware of the shortcut for testing a string for empty / non-empty. Such a candidate might produce a more concise solution, as follows...

CONCISE SOLUTION

function splitListStrUsingComma (sourceStr) {
  return sourceStr ? sourceStr.split (',') : [];
}

If the candidate doesn't produce the concise solution right off the bat, ask them how they might optimize their solution for size.

3.10.1. The Twist

If by this point you've established that the candidate has some promise, then you can unleash the next challenge: write a single line that will accomplish the same thing and that will only dereference the source string once!

THE TRICKY SOLUTION

function splitListStrUsingComma (sourceStr) {
  return (sourceStr + ',').replace (/^,$/,'').split (',').slice (0,-1);
}

In this solution, we add an element to the list - from the perspective of the split method - by appending a "comma". Then we replace the entire string with an empty string if the string is only a comma. We split the string with comma as the delimiter, and then we remove the last element using the slice method of the Array object, specifying a negative value for its second parameter. For a single non-empty element, where the source string has no comma, the slice method ends up operating on an array with two elements - the last one being empty. In fact, for any non-empty source string, the last element ends up being the empty added element. But for the empty source string case, the replace results in there only being one element after the split is performed, and this element is removed by the slice - exactly the behavior we're after.

Naturally, one would never use such code in real life, but the aim of this question is to plumb the depths of a candidate's knowledge of the JavaScript language. There's a lot that the candidate needs to know in order to arrive at this solution. When the candidate is stuck in a locked room and the bomb is ticking, does the candidate have the MacGyver sense to use what's available to save the day? Does the candidate even know and understand what all is available for them to use? A good candidate will find the question's constraints an interesting puzzle and should not become frustrated / annoyed with the question.

EVEN BETTER TRICKY SOLUTION

function splitListStrUsingComma (sourceStr) {
  return sourceStr.replace (/(.)$/,'$1,').split (',').slice (0,-1);
}

Here we're adding an extra element, only if the source string is non-empty. We append a comma to a non-empty string by using a regular expression that replaces the last character with that character followed by a comma.

Return to QUESTION: Split List String, Using Comma