Although typeof bar === "object"
is a reliable way of checking if bar
is an object, the surprising gotcha in JavaScript is that null
is also considered an object!
Therefore, the following code will, to the surprise of most developers, log true
(not false
) to the console:
var bar = null;
console.log(typeof bar === "object"); // logs true!
As long as one is aware of this, the problem can easily be avoided by also checking if bar
is null
:
console.log((bar !== null) && (typeof bar === "object")); // logs false
To be entirely thorough in our answer, there are two other things worth noting:
First, the above solution will return false
if bar
is a function. In most cases, this is the desired behavior, but in situations where you want to also return true
for functions, you could amend the above solution to be:
console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function")));
Second, the above solution will return true
if bar
is an array (e.g., if var bar = [];
). In most cases, this is the desired behavior, since arrays are indeed objects, but in situations where you want to also false
for arrays, you could amend the above solution to be:
console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]"));
However, there’s one other alternative that returns false
for nulls, arrays, and functions, but true
for objects:
console.log((bar !== null) && (bar.constructor === Object));
Or, if you’re using jQuery:
console.log((bar !== null) && (typeof bar === "object") && (! $.isArray(bar)));
ES5 makes the array case quite simple, including its own null check:
console.log(Array.isArray(bar));
Since both a
and b
are defined within the enclosing scope of the function, and since the line they are on begins with the var
keyword, most JavaScript developers would expect typeof a
and typeof b
to both be undefined in the above example.
However, that is not the case. The issue here is that most developers incorrectly understand the statement var a = b = 3;
to be shorthand for:
var b = 3;
var a = b;
But in fact, var a = b = 3;
is actually shorthand for:
b = 3;
var a = b;
As a result (if you are not using strict mode), the output of the code snippet would be:
a defined? false
b defined? true
But how can b
be defined outside of the scope of the enclosing function? Well, since the statement var a = b = 3;
is shorthand for the statements b = 3;
and var a = b;
, b
ends up being a global variable (since it is not preceded by the var
keyword) and is therefore still in scope even outside of the enclosing function.
Note that, in strict mode (i.e., with use strict
), the statement var a = b = 3;
will generate a runtime error of ReferenceError: b is not defined
, thereby avoiding any headfakes/bugs that might othewise result. (Yet another prime example of why you should use use strict
as a matter of course in your code!)
The above code will output the following to the console:
outer func: this.foo = bar
outer func: self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
In the outer function, both this
and self
refer to myObject
and therefore both can properly reference and access foo
.
In the inner function, though, this
no longer refers to myObject
. As a result, this.foo
is undefined in the inner function, whereas the reference to the local variable self
remains in scope and is accessible there.
This is an increasingly common practice, employed by many popular JavaScript libraries (jQuery, Node.js, etc.). This technique creates a closure around the entire contents of the file which, perhaps most importantly, creates a private namespace and thereby helps avoid potential name clashes between different JavaScript modules and libraries.
Another feature of this technique is to allow for an easily referenceable (presumably shorter) alias for a global variable. This is often used, for example, in jQuery plugins. jQuery allows you to disable the $
reference to the jQuery namespace, using jQuery.noConflict()
. If this has been done, your code can still use $
employing this closure technique, as follows:
(function($) { /* jQuery plugin code referencing $ */ } )(jQuery);
The short and most important answer here is that use strict
is a way to voluntarily enforce stricter parsing and error handling on your JavaScript code at runtime. Code errors that would otherwise have been ignored or would have failed silently will now generate errors or throw exceptions. In general, it is a good practice.
Some of the key benefits of strict mode include:
this
coercion. Without strict mode, a reference to a this
value of null or undefined is automatically coerced to the global. This can cause many headfakes and pull-out-your-hair kind of bugs. In strict mode, referencing a a this
value of null or undefined throws an error.function foo(val1, val2, val1){}
), thereby catching what is almost certainly a bug in your code that you might otherwise have wasted lots of time tracking down.
var object = {foo: "bar", foo: "baz"};
) but as of ECMAScript 2015 this is no longer the case.eval()
behaves in strict mode and in non-strict mode. Most significantly, in strict mode, variables and functions declared inside of an eval()
statement are not created in the containing scope (they are created in the containing scope in non-strict mode, which can also be a common source of problems).delete
. The delete
operator (used to remove properties from objects) cannot be used on non-configurable properties of the object. Non-strict code will fail silently when an attempt is made to delete a non-configurable property, whereas strict mode will throw an error in such a case.Surprisingly, these two functions will not return the same thing. Rather:
console.log("foo1 returns:");
console.log(foo1());
console.log("foo2 returns:");
console.log(foo2());
will yield:
foo1 returns:
Object {bar: "hello"}
foo2 returns:
undefined
Not only is this surprising, but what makes this particularly gnarly is that foo2()
returns undefined without any error being thrown.
The reason for this has to do with the fact that semicolons are technically optional in JavaScript (although omitting them is generally really bad form). As a result, when the line containing the return
statement (with nothing else on the line) is encountered in foo2()
, a semicolon is automatically inserted immediately after the return statement.
No error is thrown since the remainder of the code is perfectly valid, even though it doesn’t ever get invoked or do anything (it is simply an unused code block that defines a property bar
which is equal to the string "hello"
).
This behavior also argues for following the convention of placing an opening curly brace at the end of a line in JavaScript, rather than on the beginning of a new line. As shown here, this becomes more than just a stylistic preference in JavaScript.
The NaN
property represents a value that is “not a number”. This special value results from an operation that could not be performed either because one of the operands was non-numeric (e.g., "abc" / 4
), or because the result of the operation is non-numeric.
While this seems straightforward enough, there are a couple of somewhat surprising characteristics of NaN
that can result in hair-pulling bugs if one is not aware of them.
For one thing, although NaN
means “not a number”, its type is, believe it or not, Number
:
console.log(typeof NaN === "number"); // logs "true"
Additionally, NaN
compared to anything – even itself! – is false:
console.log(NaN === NaN); // logs "false"
A semi-reliable way to test whether a number is equal to NaN is with the built-in function isNaN()
, but even using isNaN()
is an imperfect solution.
A better solution would either be to use value !== value
, which would only produce true if the value is equal to NaN. Also, ES6 offers a new Number.isNaN()
function, which is a different and more reliable than the old global isNaN()
function.