JavaScript Quirks

If JavaScript were a human language, it would probably be English--you can't ignore it, it's super useful, and if you try to learn it, it often sometimes doesn't make sense and you get smacked in the face by the "gotchas".

A friend recently sent me Dmitry Baranovskiy's short quiz he published in 2009 called "So, you think you know Javascript?".

Go check out the quiz and see if you can correctly guess the answers. There are only five questions, but some of them will probably have you scratching your head.

Answers to 'So, You Think You Know Javascript?'

#1

if (!("a" in window)) {
    var a = 1;
}
alert(a);

Did you initially think you would get alerted with a 1? Then you are a logical human being!...but you are wrong in this crazy JavaScript land.

There are two things to remind yourself of:

  1. the global window object
  2. "floating" variable declarations

The Global Window Object

Whenever you declare a global variable, it becomes a property of the window. I think of the window as a giant object that envelops all of your code.
Thus, whenever you write var a = 1, it's equivalent to writing window.a = 1. You are declaring a variable to this global window object.

And because of that, you can also check to see if a global variable has been declared.

a in window //-> true

Floating Variable Declarations

All variable declarations are brought to the top of whatever scope they're contained in.

When the JavaScript engine runs your code, it first looks for all variable declarations and floats them to the top.

Do not mistake variable declarations for variable initializations.

This is the most important part of understanding #1.

Variable declarations and variable initializations need to be thought of as two separate operations in JavaScript.

When you have the line var a = 1, it is both a variable declaration and an initialization. So the engine reads it as this:

var a; //<--declaration
a = 1; //<--initialization

So how does the JavaScript engine look at our initial problem?

var a;
if (!("a" in window)) {
    a = 1;
}
alert(a);

The engine understands this code as having the variable 'a' declared first, THEN followed by the if-statement. And of course, since we already have the variable declared, that if-statement condition is false and 'a' is never assigned a value of 1.

answer: undefined

#2

var a = 1,
    b = function a(x) {
        x && a(--x);
    };
alert(a);

Ok, I got the answer relatively painlessly. The way I understood #2 is that while 'b' is doing a bunch of things to 'a', 'a' is never outright changed.

But there are some good underlying concepts that need some proper attention:

  1. function declarations and expressions
  2. override hierarchies

Function Declarations and Expressions

Like variable declarations, function declarations are also floated to the top of the containing scope along with variable declarations:

function a(x) {
	x && a(--x);
};

However, function expressions (like variable initializations) are not.

var functionExample = function(a, b) {
	return a+b;
};

Override Hierarchies

There's a hierarchy to everything that the JavaScript engine follows.

Override heirarchy:

variable initializations > function declarations > variable declarations

In other words, function declarations override variable declarations but not variable initializations.

Examples:

function greeting(){
    return "hello";
}
var greeting;
alert(typeof greeting);  //-> "function"

Even though the variable is declared after the function declaration, the function declaration takes precendence. Thus, "function" is returned.

But if you turn that function declaration into a variable initialization, it overrides the function declaration.

function greeting() {
	return "hello";
}
var greeting = "hihi";
alert(typeof greeting); //-> "string"

answer: 1

#3

function a(x) {
    return x * 2;
}
var a;
alert(a);

This is a lot like the second question. Again, going back to override hierarchies, there is no variable initialization so the function declaration is what we get in return.

answer:
function a(x) {
    return x * 2;
}

#4

function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);

This should be straight forward: the arguments you're putting through function b are 1, 2, and 3. The function takes the second index in the arguments (which would be a, which is 3) and sets it to 10.

answer: 10

#5

function a() {
    alert(this);
}
a.call(null);

Here is a method (.call()) being called on a, which is really just the 'this' object. A quick definition for a method is that it's just a function that's attached to an object.

Thus, the 'this' here refers to the global window.

answer: object Window

Resources

Javascript Garden - More cool JavaScript quirks!

Dmitry's Test - The original test

Is there anything I missed? Let me know by commenting below!