Few days ago I met a very interesting JS interview question. It claims that this question covered almost all aspect that every JS programmer should understand. And here is the question:
For me, I only managed to answer 5 of them correctly. After that I did some research and figured the correct answers with corresponding explanation.
Let’s look at them one by one.
This should be quite straightforward.
getName property in
Hence, the alert value will be 2 .
This one is rather confusing. Because if you check the declaration of
getName, there are two of them there:
Both of them will work for
getName(), but which one to use? Naturally, we think since the later function declaration will overwrite the first “Anonymous” function expression, and hence the answer is 5 . However, this is not true.
Consider following code
What do you expect to be printed in the console.log(..) statement? error? undefined? 2?
Many of us will think how can you use a variable before you declare it? So it seems that a
ReferenceError will be thrown.
However, surprisingly, it will print undefined.
Well, it’s all about compiler .
When the compiler sees a variable declaration, such as
var a = 2;, it does not think of that as one statement. It actually thinks of it as two statement:
var a; and
a = 2;. The first statement, the declaration, is processed during the compilation phase. The later statement, the assignment, is left in place for the execution phase. Declarations are raised to top by compiler, and this is what we called Hoisting .
So the example we saw just now, in compiler’s perspective, is like this:
And it’s quite clear that why
undefined will be printed.
In addition, both function declarations and variable declarations are hoisted. Which one first? For the same name of “duplicate” declarations, functions are hoisted first, and then variables.
1 will be printed instead of
2. Because the compiler will see it as:
var foo was the duplicate (and thus ignored) declaration, even though it came before the function declaration, because function declarations are hoisted before normal variables.
So back to our question, a more precise view of the order are:
And hence, when we called
getName(), we will print 4 .
Next, let’s consider
What will be returned by
It will return
this, a keyword that confuses thousands of programmers. In Java,
this represents the object itself, does it apply the same rule here?
In most cases, the value of this is determined by how a function is called. This is not assigned a value until an object invokes the function where this is defined. So a very simple rule is always know how your function is invoked .
Consider the following example:
To understand why
foo() return 1, can you find out where
foo() is called? Actually it is called in global scope, a.k.a, called by the global
window object. And hence this will refer to the
window object, and find the value of variable
How about this example:
In this case, foo() is called by obj. So
this will refer to the
obj object. So
this.a will try find a variable from
obj and hence evaluated as “not 1”;
To find more about
this keyword, checkout this book
Back to our question, now we know
foo() is called in global scope, and hence
this will refer to
window object. So is it true that it will also alert 4 as last question since it’s the same as
Well, 4 is still incorrect. Look more carefully,
Foo() will do another thing, which is assigning an anonymous function to
getName variable. What is important here is this
getName variable does not come with any declaration. The key takeaway here is that if an variable is used without any declaration, it will by default defined in the global scope, a.k.a
window object. But we already have that
getName in global scope! Therefore, it will overwrite the
getName variable defined in global scope. And hence, it will actually alert 1 .
Next, we now call the global defined
getName variable again. Since it got overwritten when we invoke
Foo().getName();, it will alert 1 as well. This is quite tricky in my opinion.
Next three lines are about operator precedence and
new keyword. You can find the priority table at here
For first one
new Foo.getName();, from the table we know that member access (.) precedes the keyword
new. So it is equivalent to
new (Foo.getName)(). We are using the
Foo.getName function as a constructor, and hence 2 will be alerted.
Things are getting more interesting at
new Foo().getName();. This is equivalent to
(new Foo()).getName(). We use
Foo as the constructor and create a new
Foo object. Then we invoke the prototype function defined for
Foo object in
and hence 3 will be alerted.
Finally, apply the same rule,
new new Foo().getName(); is equivalent as
new ((new Foo()).getName)();. An instance of
Foo will be created. And we use its
getName function as the constructor. So again, 3 will be alerted.