Answering the Juriy Zaytsev JavaScript Quiz

February 9th, 2010  |  Published in JavaScript  |  6 Comments

Juriy Zaytsev (aka kangax) made a really nice JavaScript quiz, which covers a lot of interesting subjects such as scoping, function expressions, variable and function declarations, references, order of evaluation, object instantiation and more.

I’ve had a great time answering those questions, and I would like to share my answers with a brief explanation.

#1


    (function(){ 
      return typeof arguments;
    })();

It will return "object", because arguments is just that, a simple object.

#2


    var f = function g(){ return 23; };
    typeof g();

The answer is Error.

A ReferenceError will be generated, because the name (Identifier) of a FunctionExpression can be referenced only from inside its FunctionBody, to allow the function to make recursive calls. Unlike with a FunctionDeclaration the Identifier of a FunctionExpression doesn’t affect the enclosing scope.

There are a lot of misconceptions about the differences between function expressions and function definitions, I would highly recommend the following article also written by kangax:

Note: In the Microsoft JScript implementation there is a bug, a serious deviation from the ECMA specification, where identifiers of function expressions leak to its enclosing scope.

#3


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

The answer is 1, because argument identifiers are created as properties of the Variable Object, (the Activation Object in the case of Function Code), following the rules of a variable instantiation for the Function Code execution context, those properties are created with the { DontDelete } attribute, so they can’t be deleted.

#4


    var y = 1, x = y = typeof x;
    x;

The answer is "undefined", because the Variable statement at parse time will define the variables (they will be “hoisted” to its enclosing scope, and initialized with the undefined value), then in execution time and due the right-to-left associativity of the AssignmentOperator the first assignment will be done (y = 1;) then, the second assignment: (y = typeof x;) that will return "undefined" and this is the value that will be used in the very last one: (x = "undefined";).

That it’s easier to realize if we reorder the statements:


var y,x; // initialized with undefined
y = 1;
y = typeof x; // x is undefined, so "undefined" is returned
x = y; // "undefined"
x;

#5


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

This one plays with the identifier names inside the scope of the function.

The answer is "number", because the FunctionExpression Identifier (the function name) is bound to the scope chain, but later is overwritten by the value of the f argument.

#6


    var foo = { 
      bar: function() { return this.baz; }, 
      baz: 1
    };
    (function(){ 
      return typeof arguments[0]();
    })(foo.bar);

The answer is "undefined", because the foo.bar function is executed with the this value pointing to the arguments object of the second function.

Remember that the function context (the this value) can be set implicitly, depending on how a function is invoked, e.g.:


foo(); // a simple function call, this will point to the global object
(function () { })();

obj.method(); // this == obj inside method
obj['method'](); 

In this question the [] property accessor is used on the arguments object, causing the context change, we are executing the foo.bar function as if it were a "method" of the arguments object.

#7


    var foo = {
      bar: function(){ return this.baz; },
      baz: 1
    }
    typeof (f = foo.bar)();

The answer is "undefined".

This case is similar to the previous one, because the assignment operator will simply return a reference to foo.bar, causing that when we invoke the function, the context point to the Global object.

#8


    var f = (function f(){ return "1"; }, function g(){ return 2; })();
    typeof f;

The answer is "number", because the Comma Operator, will return the value of the second operand, in this case a reference to the g function, that will be invoked and f will contain the returned 2 number literal. For example:


  (1,2) == 2; // true

#9


    var x = 1;
    if (function f(){}) {
      x += typeof f;
    }
    x;

The answer is "1undefined", because the condition expression of the if statement is a Function Expression, it will evaluate to true and the if block will be executed, but the f identifier it's not available.

Inside the if statement, the typeof operator returns a String ("undefined" since f doesn't exist), and that causes the String concatenation when the += operator is used.

The following can help to realize it:


    var x = 1;
    if (true) {
      x += typeof f; // f is not defined
    }
    x; // "1undefined"

Note: In JScript implementations due the bug I mentioned early, the result of this code will be "1function" which is not correct.

#10


    var x = [typeof x, typeof y][1];
    typeof typeof x;

The answer is "string".

The first statement is just trying to confuse you, because as you know, the typeof operator will return always a String value, so you can figure out why typeof typeof anything; will return always "string" also.

#11


    (function(foo){
      return typeof foo.bar;
    })({ foo: { bar: 1 } });

The answer is "undefined", because as the foo argument, we are passing this object: { foo: { bar: 1 } }.

foo.bar doesn't exist, the bar property is actually accessible by foo.foo.bar.

#12


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

The answer is 2, because Function Declarations are "hoisted" at parse time, the second f function will replace the first one, even if the second is defined after the return statement.

#13


    function f(){ return f; }
    new f() instanceof f;

The answer is false because the actual object that is instance of f, is the this value within the constructor, and returning a non-primitive from a constructor, causes that this object with the right [[Prototype]] property (this) to be lost.

So basically, f is not an instance of f, since:


    new f() == f; // true

We can check that behavior by looking how the [[Construct]] internal operation works.

#14


    with (function(x, undefined){}) length;

The answer is 2, because the with statement augments the scope chain with the properties of the passed object, in this case a function.

The length property of functions objects contains the number of expected arguments, in this case two arguments.

Note: undefined has no special meaning, is just another identifier, in this example is used as an argument in the FormalParameterList.

Tags: ,

Responses

  1. Tweets that mention Answering the Juriy Zaytsev JavaScript Quiz :: CodingSpot -- Topsy.com says:

    February 9th, 2010 at 6:59 am (#)

    [...] This post was mentioned on Twitter by kangax, jakescott, wpbasti, wpbasti, mlennox and others. mlennox said: cool – answers and explanations http://bit.ly/9NXOl0 for this javascript quiz http://bit.ly/a25MAx [...]

  2. kaba says:

    February 10th, 2010 at 7:52 am (#)

    Thank you!

    This is a perfect complement to the quiz. The hardest answer for me to get my head around is #13, but I think that’s because I haven’t fully understood how the new-keyword works in JS. :)

  3. Ben Cherry says:

    February 11th, 2010 at 1:20 am (#)

    Well, that is a straightforward explanation. Great work!

  4. Какво ново във втората седмица на Февуари | NeXt says:

    February 13th, 2010 at 12:05 pm (#)

    [...] Answering the Juriy Zaytsev JavaScript Quiz – за тези, които много са се затруднили с теста на kangax, ето ги и отговорите с обяснения. [...]

  5. Alex Lievano says:

    July 22nd, 2010 at 2:48 am (#)

    I took this quiz a few months ago and puzzled over a few (okay, more than a few) of the answers. I admire the depth of your JavaScript knowledge as shown in your answers on SO, so this is great! Thanks for the writeup.

  6. Sarfraz Ahmed says:

    May 4th, 2012 at 1:55 am (#)

    Great stuff, thanks for sharing man :)

Leave a Response