Test your JavaScript skills with js-assessment

I recently discovered js-assessment, a “test-driven approach to assessing JavaScript skills” created by Rebecca Murphey. The js-assessment application contains a series of tests designed to assess a job candidate’s grasp of JavaScript, but it can also be used to gauge your own knowledge of the language. Think of it as a mini Project Euler for JavaScript.

The questions are divided into five topics covering different aspects of the language: arrays, objects and context, functions, asynchronous behavior and Backbone views. If, like me, you have a decent grasp of JavaScript, but wouldn’t feel confident writing “JavaScript programmer” on your curriculum vitae, then I think you’ll find the tests an enjoyable challenge. None of the questions are super difficult, though I confess to needing help from MDN to arrive at a few of the solutions. I definitely learned a thing or two about JavaScript along the way.

Because Rebecca’s application is built in Node, you’ll need to have Node and NPM installed before you can run it. That’s a shortcoming I think, since it throws up a fairly large barrier-to-entry, but if you’re serious about JavaScript then you really ought to delve into Node anyway. I won’t bore you with instructions for installing Node – you can do it using Homebrew or download an installer from the official Node website. After that, just follow the steps on the js-assessment github and you’ll be up and running.

Rebecca seems undecided about whether to publish solutions to the tests, but in the name of sharing the knowledge (and at the risk of exposing my own shortcomings as a programmer), you’ll find my answers below. My solutions won’t make much sense taken out of context like this, but once your start working your way through js-assessment things will become a lot clearer.

Although my solutions pass Rebecca’s tests I’m sure some of them could be improved, so if you have suggestions for optimizing my code please leave a comment below.

Arrays

1. You should be able to determine the location of an item in an array

fn = function (arr, targ) {
  for (var pos=0; pos < arr.length; pos++){
    if (arr[pos] == targ){
      return pos;
    }
  }
};

2. You should be able to add the values of an array

fn = function (arr) {
  var total = 0;
  for (var pos=0; pos < arr.length; pos++) {
    total += arr[pos];
  }
  return total;
};

3. You should be able to remove an item from an array

fn = function (arr, itemToRemove) {
  for (var pos=0; pos < arr.length; pos++){
    if (arr[pos] == itemToRemove){
      var removedItem = arr.splice(pos,1);
    }
  }
  return arr;
};

4. You should be able to add an item to the end of an array

fn = function (arr, itemToAdd) {
  arr.push(itemToAdd);
  return arr;
};

5. You should be able to create an array from two arrays

fn = function (arr1, arr2) {
  var arr = arr1.concat(arr2);
  return arr;
};

6. You should be able to add an item anywhere in an array

fn = function (arr, itemToAdd, pos) {
  arr.splice(pos, 0, itemToAdd);
  return arr;
};

Objects and context

1. You should be able to alter the context in which a method runs

fn = function () {
  // Call the sayIt() function and pass it the
  // 'b' object as its context.
  return a.sayIt.call(b);
};

2. You should be able to alter multiple objects at once

fn = function (greeting) {
  C.prototype.greeting = greeting;
};

3. You should be able to iterate over an object’s ‘own’ properties

fn = function (obj) {
  var ownProperties = [];
  for (var prop in obj) {
    // hasOwnProperty returns true if the property
    // belongs to the object, not its prototype chain.
    if (obj.hasOwnProperty(prop)) {
      ownProperties.push(prop + ': ' + obj[prop]);
    }
  }
  return ownProperties;
};

Functions

1. You should be able to use an array as arguments when calling a function

fn = function (opts) {
  // Call the sayIt() function in the context of 'this'
  // and pass it the 'opts' array.
  return sayIt.apply(this, opts);
};

2. You should be able to change the context in which a function is called

fn = function (opts){
  // Call the speak() function in the context of 'obj'.
  return speak.call(obj);
};

3. You should be able to return a function from a function

fn = function (prefix) {
  var concatFn = function(suffix) {
    return prefix + ', ' + suffix;
  };
  return concatFn;
};

4. You should be able to create a ‘partial’ function

fn = function (func, greeting, name) {
  var partialFn = function(punctuation) {
    return func(greeting, name, punctuation);
  };
  return partialFn;
};

Async behavior

1. You should understand how to uses ‘promises’

As far as I know promises are not part of the JavaScript language, and need to be implemented using a third party library. In my solution I used jQuery’s deferred object to return a promise.

fn = function () {
  // This is a contrived example to demonstrate that the promise
  // is returned asynchronously after a 1sec timeout.
  var dfd = $.Deferred();
  var timeoutID = window.setTimeout(function(){
    dfd.resolve(true);
  }, 1000);
  return dfd.promise();
};

2. You should be able to receive data from the server and manipulate it

var get = $.ajax({
  url: url
});

// Since jQuery's $.ajax returns a promise, we can use
// .done and .fail callbacks.
get.done(function(response){
  peopleArray = [];
    for (var person in response.people){
      peopleArray.push(response.people[person].name);
    }
    peopleArray.sort(); // Not required in this case.
    tests();
});

get.fail(function(){
  console.log('Load failed');
});

Backbone views

This section of the test relies on knowledge of the Backbone framework. Personally that doesn’t bother me since I have used Backbone before, but I’m not sure that Backbone knowledge should be considered mandatory for a JavaScript professional.

1. You should be able to render a view using a template

var MyView = Backbone.View.extend({
  template : tpl,
  render : function() {
    // This could be written on a single line, but I've
    // split across 3 lines for readability:
    var compiledTemplate = _.template(this.template);
    var viewHTML = compiledTemplate(this.model.toJSON());
    $('body').append(viewHTML);
  }
});

2. You should be able to update the view when the model changes

var MyView = Backbone.View.extend({
  initialize : function() {
    this.model.bind('change:greeting', this.render, this);
    this.model.set({greeting: 'Goodbye, world'});
  },
  template : tpl,
  render : function() {
    $('#my-view').html(this.model.get('greeting'));
  }
});

9 thoughts on “Test your JavaScript skills with js-assessment

  1. Thomas says:

    Thanks for sharing: I was stuck on some cases.
    I’ve seen you’re looping in array examples 1 and 3,
    I think you’d better use build-in function indexOf

    1. You should be able to determine the location of an item in an array
    fn = function(arr, val) {
      return arr.indexOf(val);
    };

    3. You should be able to remove an item from an array
    fn = function (arr, val) {
      var pos = arr.indexOf(val);
      arr.splice(pos,1);
      return arr;
    };

    Regards

  2. Jonathan says:

    @Thomas Awesome! That’s exactly why I posted my solutions, to get those sort of suggestions.

  3. Ali says:

    Great stuff! I was stuck for a while on the “closures” one in the functions section…. but cracked it eventually. “Ahhh, closure”, I said to myself

  4. Jonathan says:

    @Ali – I think I answered questions 3 and 4 in the functions section using closures, but I did so naively, I can assure you!

  5. Tony says:

    Thanks for posting these! It’s helpful to see how someone else solved the same problem. I used the same approach as you for the Arrays, and like Thomas’ alternative.

    For the partial function (Functions 4), I had to do quite a bit of reading to figure it out. I ended up relying on this article:
    http://www.drdobbs.com/open-source/231001821?pgno=2

    It helped me understand exactly what was going on and how to create a generic partial function creator.

    function schonfinkelize(fn) {
        var slice = Array.prototype.slice
        , stored_args = slice.call(arguments, 1);
        return function () {
            var new_args = slice.call(arguments)
            , args = stored_args.concat(new_args);
            return fn.apply(null, args);
        };
    }

  6. Jonathan says:

    @Tony Thanks for the link. The ‘partials’ question is the one that had me scratching my head too.

  7. Daniel says:

    @Tony

    That looks more like a implementation of a curry function rather than a partial function.

  8. Dan Shappir says:

    Here are some suggestions for some of the questions:

    For Arrays #2:

    function sum(a) {
    return a.reduce(function(p,c) { return p + c; }, 0);
    }

    For Arrays #3 – returns new array with all items of value v removed:

    function remove(a, v) {
    return a.filter(function (x) { return x === v; });
    }

    Objects and context #1 – this way you can also pass arguments to the method:

    function alterContext() {
    return a.someMethod.apply(b, arguments);
    }

  9. Jaxolotl says:

    @Thomas

    Consider that array.indexOf(x) calls on IE8 will fail. ;) due to an IE8 lack of implementation

Comments are closed.