The interview on Javascript: road map, tips and tricks

If you know how to change on the fly the prototypes of the things
If you feel as a ruler of the HTML Universe and as the master of the World DOM Tree,
If you know where events leave and what time of the life cycle is the best to hunt them,
If you own a spell of closures and is able to give the functions eternal life,
If  in your weapon set are always sharpened both short and long ‘equals’,
If you no longer surprised that 2 + “2″ = “22″,
So you are the one we are looking for

A description of the Javascript Developer vacancy

            As a rule travelers compose their travel notes to express the impressions of the lands they visited. I guess the Javascript-interview is also a kind of virtual land. And I visited it several times either as a guest or as a citizen. So I have my own impressions about this place and I’d like to share them.

My travel notes about the Javascript-interview-land consist of two parts: general “geographical” position and some tips and tricks how behave its “aborigines” and what you should know to get succeed with them.

General position: the road map


           1

First of all, let’s consider it at the bird-eye-view. Modern Javascript is an exciting and immense territory. I think if Terry Pratchett was writing about it, he would describe it somewhat like Octavo that was not just a book of the spells, but turned to be a basis of the World. The similar way, Javascript turned not to be a simple tool that serve to enliven web pages and amuse the users, but it creates and govern the worlds of the Web Universe.

In spite of this, there is not too many sides you meet in the Javascript-interview-land. Don’t ask me why, I don’t know. Let’s list them all:

  1. Data types.
  2. Type transformations
  3. Functions. Scopes of the variables. Invocation.
  4. Closures.
  5. Objects. Creating objects. Context. Inheritance.
  6. setInterval() and setTimeout()
  7. Events.
  8. Core objects: String, Array, Date, RegExp.

Of course, you may face with some different things. But if you pass ten interviews, eight of them will contain only those listed above.

Data types

js2

It’s so funny: every Java developer starting from Junior knows eight primitive Java types. But even some Senior Javascript developers cannot list five primitive Javascript types. Please, remember: “number”, “string”, “boolean”, “null”, “undefined”. All others are “object”. Yes, including arrays and functions! You may check it using typeof operator. Just remember about two exceptions:

typeof null //-> “object” – it’s a recognized mistake kept however for the back compatibility

typeof function(){} //-> “function” – it’s so for every function

 

Each primitive (but null and undefined) has its own objective wrapper. For example:

var x = 5;

var y = new Number(5);

typeof x //-> “number”

typeof y //-> “object”

 

And there are two unusual numbers: NaN and Infinity. Be aware that

NaN == NaN //-> false

So, if you need to check NaN, use global core function isNaN():

isNaN(NaN) //-> true

isNaN(5) //-> false

 

Type transformations

3
            The almost problems in type transformations come out on operations (binary and unary) and data comparison. However let’s notice that there are not the only cases of type transformations. For example, function alert() takes a string. If not, corresponding obj.toString() function runs on its argument obj. And there is a king of “autounboxing” when object methods of String, Number and Boolean are applicable to corresponding primitives.

We will not enter the theory of this phenomenon, it’s described fully in Ecma-262 specification. And it’s really boring enough. For the most of practical cases it’s enough to know a few of simple rules:

  1. Boolean operations (both binary and unary) convert all operands to boolean. That is why one can use !! to convert anything to boolean.
  2. Conversion to boolean is simple: null, undefined, 0 and empty string “” are false, all others are true.
  3.  Math operator + is used also for string concatenation. That is why when one operand is string another one is converted to string anyway.
  4. Other math operators require conversion to number. If this is impossible it returns NaN.

5. So, one can use + for conversion string to number. However it works not the same way as parseInt(), parseFloat() because it doesn’t try to parse:
parseInt(“5x”) //-> 5

+”5x” //-> NaN

6. Objects are converted to string via application of their own toString(). For example, array is converted by following way:
[1,2,3].toString() //-> “1,2,3″

[].toString() //-> “”

  1. Strings compare lexicographically.
  2. And we should know that comparison with “==” does transforms types while “===” returns false for different types.
Try yourself.

Give the result in each of these cases:

  1. !!(new Boolean(false))
  2. typeof {} == typeof []
  3. {myKey: 1}=={myKey: 1}
  4. “Hello World” === true
  5. “1″ + 2 + 3
  6. 1 + 2 + “1″
  7. null == undefined
  8. “a” > “A”
  9. [] + []
  10. ![]
  11. +![]
  12. +!![]
  13. ![] + []
  14. !![] + []
  15. [][[]] + []
  16. (!![] + [])[+![]]

 

Functions. Scopes of the variables. Invocation

4

The scopes of the variables in Javascript are determined only by the scope of the function. Then, the scope of the function is determined only by the key word var. If you use this key word within definition of some function, corresponding variable shadows the outer variable having the same name. Otherwise the outer variable is visible in the interior function. Neither curl brackets nor somewhat else impact the scope. You may see  an example at the illustration above. This illustration is borrowed from http://odetocode.com/Blogs/scott/archive/2007/07/10/closure-on-javascript-closures.aspx. You may see also http://habrahabr.ru/post/149526/ and http://habrahabr.ru/post/239863/ for more detailed discussion. An interesting thing is hoisting of variables. It means that all the variable declarations hoist at the very top of the function definition. Even from within of the loop or conditional blocks. But it concerns only variable declarations, not assignment of value.

Function can be invoked using brackets () or by the methods call() or apply(). First argument in these functions is context (see more below). Then, all other arguments in call() are corresponding function parameters. What bout apply() it takes the only second parameter which is an array of all the function’s parameter. Even if a function takes one parameter, in apply() it should be passed as an array with one element.

Another tricky thing frequently used in modern Javascript is immediately invoked function. It is used in order not to pollute the global scope. There are two forms of it:

(function(){})()

!function(){}()

Of course its body in the curl brackets should contain something useful. And it can be invoked with immediately passed arguments.

Try yourself.

Give the result in each of these cases:

  1. function plus(arg1, arg2){

arg2 = arg2 || 10;

console.log(arg1+arg2);

}

plus(1,2);

plus(1,0);

plus(3);

  1. var a = 1;

       function f(b){

if (b == 0){

a = 2

} else {

var a = 3

}

}

f(1);a;

f(0);a;

  1. (function f(f){

return typeof f();

})(function(){ return 1; });

 

Closures

5

Javascript contains some elements of functional programming. One of those is “functions as a first class citizens”. It means that function can be used as data and correspondingly they can be passed as an arguments and can can be returned by another function. Correspondingly, the returned function should remember how it was created, in other words it should keep context of the function returning it. This is the thing called as “closure”. You may learn more interesting things about closures here http://habrahabr.ru/post/38642/.

Try yourself.
  1. Imagine we have an HTML containing 10 elements <div>. We need to number these elements and add listeners to each of them. Each listeners should show alert with the number of corresponding div on click. We did it by the following way:
    var divs = document.getElementsByTagName(‘div’);
    for(var i=0; i<10; i++) {

divs[i].innerHTML = i

divs[i].onclick = function(){ alert(i) }

}
What one get on click?

  1. How to fix the previous code?
  2. Write a function sum that sum(x)(y) returns x + y
  3. Generalize the previous task for any number of items.

 

Objects. Creating objects. Context

6

Objects in Javascript are simple pairs key – value. Key is always a string. If you try use not a string it will be converted to a string. Value may be whatever valid data type. Objects always are passed by reference. Even literal objects. That is why
{} == {} //-> false
Then,  every function can be used as a constructor of object with the key word new:
var obj = new f()
When object is created this way, several things happen:

  1. A new empty object is created.
  2. The reference to this object is assigned to the key word this. This is context of the object.
  3. The constructor function runs with assigned context.
  4. The property this.constructor is  assigned to the function used for creating the object.
  5. Constructor returns a value. If it in its body return nothing or some primitive value – it returns the created object. If it in its body return any object – this object is returned instead of created one.

Two other ways is creating a literal object or use static function Object.create(). The first argument of this function assigns prototype (see below) and the second one contains value descriptors.

The inheritance in Javascript is based on the concept of prototype. Also it may be organized using so called “Rent-a-Constructor”. There are various combinations of these approaches described in “JavaScript Patterns” by Stoyan Stefanov. For more deep studies you may see also http://habrahabr.ru/post/149516/ and  http://habrahabr.ru/post/48542/.

Try yourself.
  1. What is the result of the following code:
    var
    A = {}, C = {};

C[A] = “A”;

A[C] = “B”;

C[A];

  1. Write realization of the operator  new as a function.
  2. Given a code:
    var a = new F();

       var b = new F();

console.log(a == b);

       function F() {};

Change F() so that  a == b would return true.

 

setInterval() and setTimeout()

7

            Please keep in your mind that these functions return a value. It’s a descriptor that gives possibility to cancel invocation:

       var descriptor1 = setTimeout(fn, 1000);

clearTimeout(descriptor1);

       var descriptor2 = setInterval(fn, 1000);

clearInterval(descriptor2);

Every function invoked by setTimeout() or setInterval() is always run on the global context. It means that within this function this is always references to window. Even when this function is a property of an object.

And usage of setTimeout(fn, 0) is also makes sense. It’s used when you need to be sure that  fn will run after all current functions are completed.

Try yourself.
  1. What is the output of this scode?
    function Dog(name) {

this.dogName = name;

}

Dog.prototype.printName = function() {

console.log(this.dogName);

}

       var myDog = new Dog(‘Fido’);

myDog.printName();

setTimeout(myDog.printName, 1000);

  1. Write your own mySetTimeout() which passes correct context.
  2. Result of the following code?
    for (i=0;i<10;i++){

setTimeout(function(){console.log(i)}, 1000)

}

  1. Rewrite the code from the previous task in order to get the expected series.

 

Events

8
            There are two phases in event life cycle: capture and bubbling. Prevent bubbling may be organized using the function event.stopPropagation() or event.cancelBubble = true (IE<9),

Very useful mean is delegation events to container. This approach is applied currently in jQuery .on() function http://api.jquery.com/on/.

Another useful thing is usage of events “mouseenter” and “mouseleave” instead of “mouseover” and “mouseout”. These events fire on a container and do not respond when mouse moves between DOM elements within this container. Cross-browser handling of these events is also organized in jQuery http://api.jquery.com/mouseenter/ and http://api.jquery.com/mouseleave/.

 

Core objects: String, Array, Date, RegExp

9

            Manipulation with strings is required. You should know how to extract required substring, find or replace a substring or a character, combine a string from several substrings.

Arrays in modern Javascript are enriched by a bunch of methods for data manipulation such as Array.prototype.map, Array.prototype.reduce and related.

Date object contains a lot of methods to create date, parse special string as a date, calculate various dates before and after.

To find corresponding regexp patterns you may use RegExp.prototype.exec() or String.prototype.match(). If you need only to check the occurrence of the pattern use RegExp.prototype.test() or String.prototype.search().

Check yourself.
  1. true
  2. true
  3. false
  4. false
  5. “123″
  6. “33″
  7. true
  8. true
  9. “”
  10. false
  11. 0
  12. 1
  13. “false”
  14. “true”
  15. “undefined”
  16. “t”
    So we can write now any word consisting of “f, a, l, s, e, t, r, u, n, d, i” using only + , ! and brackets.
  17. 3
    11
    13
  18. 1
    1
    Hoisting plus shadowing!
  19. “number”
  1. “10” on each alert.
  2. One way:
    for(var i=0; i<10; i++) {
    divs[i].innerHTML = i;
    divs[i].onclick = (function(x) {
    return function() { alert(x); };
    })(i);
    }
    Another way:
    for(var i=0; i<10; i++) {
    divs[i].innerHTML = i;
    (function(x){
    divs[x].onclick = function(){ alert(x); };
    })(i);
    }
    Use closure to fight the closure!
  1. function sum(x){

return function(y){

return x + y;

}

}

  1. function sum(x){

var res;

if (arguments.length === 0){

res = sum.res;

sum.res = 0;

} else {

sum.res |= 0;

sum.res += x;

res = sum;

}

return res;

};
Usage:
sum(1)(2)(3)()

 

function sum(x){

sum.toString = function(){

var res = sum.res;

sum.res = 0;

return res

}

sum.res |= 0;

sum.res += x;

return sum;

}
Usage:

alert(sum(1)(2)(3))

  1. “A”
  2. function nova(f, args) {

var obj = Object.create(f.prototype),

res = f.apply(obj, args),

type = typeof res;

return (type == ‘object’ || type == ‘function’) ? res : obj;

}

  1. function F() {return Object};
  2. ‘Fido’
    undefined
  3. function mySetTimeout(fn, ms, context) {
    return setTimeout(function(){fn.call(context, arguments);}, ms);

}

  1. 10 ten times
  2. Using closure:
    for
    (i=0;i<10;i++){

!function(x){

setTimeout(function(){console.log(x)}, 1000)

}(i)

}

Using recursion:

       function f(x){

if(x) {

console.log(x);

setTimeout(function(){f(x-1)},1000);

}

}

f(10);

 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>