buy the book to support the author.
Chapter 23. Standard Global Variables
This chapter is a reference for the global variables standardized by the ECMAScript specification. Web browsers have more global variables, which are listed on MDN. All global variables are (own or inherited) properties of the global object (window
in browsers; see The Global Object).
Constructors
For details on the following constructors, see the sections indicated in parentheses:
Array
(The Array Constructor)Boolean
(Wrapper Objects for Primitives)Date
(The Date Constructor)Function
(Evaluating Code Using new Function())Number
(Wrapper Objects for Primitives)Object
(Converting Any Value to an Object)RegExp
(Creating a Regular Expression)String
(Wrapper Objects for Primitives)
Error Constructors
For details on these constructors, see Error Constructors:
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
Nonconstructor Functions
Several global functions are not constructors. They are listed in this section.
Encoding and Decoding Text
The following functions handle several ways of URI encoding and decoding:
encodeURI(uri)
- Percent-encodes special characters in
uri
. Special characters are all Unicode characters except for thefollowing ones:
URI characters:
; , / ? : @ & = + $ #
Not encoded either:
a-z A-Z 0-9 - _ . ! ~ * ' ( )
For example:
- > encodeURI('http://example.com/Für Elise/')
- 'http://example.com/F%C3%BCr%20Elise/'
encodeURIComponent(uriComponent)
- Percent-encodes all characters in
uriComponent
, except for:
Not encoded:
a-z A-Z 0-9 - _ . ! ~ * ' ( )
In contrast to encodeURI
, characters that are significant in URLs and filenames are encoded, too. Youcan thus use this function to turn any text into a legal filename or URL path segment. For example:
- > encodeURIComponent('http://example.com/Für Elise/')
- 'http%3A%2F%2Fexample.com%2FF%C3%BCr%20Elise%2F'
decodeURI(encodedURI)
- Decodes a percent-encoded URI that has been produced by
encodeURI
:
- > decodeURI('http://example.com/F%C3%BCr%20Elise/')
- 'http://example.com/Für Elise/'
encodeURI
does not encode URI characters and decodeURI
does not decode them, even if they have beencorrectly encoded:
- > decodeURI('%2F')
- '%2F'
- > decodeURIComponent('%2F')
- '/'
decodeURIComponent(encodedURIComponent)
- Decodes a percent-encoded URI component that has been produced by
encodeURIComponent
. In contrast todecodeURI
, all percent-encoded characters are decoded:
- > decodeURIComponent('http%3A%2F%2Fexample.com%2FF%C3%BCr%20Elise%2F')
- 'http://example.com/Für Elise/'
The following are deprecated:
escape(str)
percent-encodesstr
. It is deprecated because it does not handle non-ASCII characters properly. UseencodeURIComponent()
instead.unescape(str)
percent-decodesstr
. It is deprecated because it does not handle non-ASCII characters properly. UsedecodeURIComponent()
instead.
Categorizing and Parsing Numbers
The following methods help with categorizing and parsing numbers:
isFinite(number)
(Checking for Infinity)isNaN(value)
(Pitfall: checking whether a value is NaN)parseFloat(string)
(parseFloat())parseInt(string, radix)
(Integers via parseInt())
Dynamically Evaluating JavaScript Code via eval() and new Function()
This section examines how one can dynamically evaluate code in JavaScript.
Evaluating Code Using eval()
The function call:
eval
(
str
)
evaluates the JavaScript code in str
. For example:
- > var a = 12;
- > eval('a + 5')
- 17
Note that eval()
parses in statement context (see Expressions Versus Statements):
- > eval('{ foo: 123 }') // code block
- 123
- > eval('({ foo: 123 })') // object literal
- { foo: 123 }
Use eval() in strict mode
For eval()
, you really should use strict mode (see Strict Mode). In sloppy mode, evaluated code can create local variables in the surrounding scope:
function
sloppyFunc
()
{
eval
(
'var foo = 123'
);
// added to the scope of sloppyFunc
console
.
log
(
foo
);
// 123
}
That can’t happen in strict mode:
function
strictFunc
()
{
'use strict'
;
eval
(
'var foo = 123'
);
console
.
log
(
foo
);
// ReferenceError: foo is not defined
}
However, even in strict mode, evaluated code still has read and write access to variables in surrounding scopes. To prevent such access, you need to call eval()
indirectly.
Indirect eval() evaluates in global scope
There are two ways to invoke eval()
:
- Directly. Via a direct call to a function whose name is “eval.”
- Indirectly. In some other way (via
call()
, as a method ofwindow
, by storing it under a different name and calling it there, etc.).
As we have already seen, direct eval()
executes code in the current scope:
var
x
=
'global'
;
function
directEval
()
{
'use strict'
;
var
x
=
'local'
;
console
.
log
(
eval
(
'x'
));
// local
}
Conversely, indirect eval()
executes it in global scope:
var
x
=
'global'
;
function
indirectEval
()
{
'use strict'
;
var
x
=
'local'
;
// Don’t call eval directly
console
.
log
(
eval
.
call
(
null
,
'x'
));
// global
console
.
log
(
window
.
eval
(
'x'
));
// global
console
.
log
((
1
,
eval
)(
'x'
));
// global (1)
// Change the name of eval
var
xeval
=
eval
;
console
.
log
(
xeval
(
'x'
));
// global
// Turn eval into a method
var
obj
=
{
eval
:
eval
};
console
.
log
(
obj
.
eval
(
'x'
));
// global
}
Explanation of (1): When you refer to a variable via its name, the initial result is a so-called reference, a data structure with two main fields:
base
points to the environment, the data structure in which the variable’s value is stored.referencedName
is the name of the variable.
During an eval()
function call, the function call operator (the parentheses) encounters a reference to eval
and can determine the name of the function to be called. Therefore, such a function call triggers a direct eval()
. You can, however, force an indirect eval()
by not giving the call operator a reference. That is achieved by retrieving the value of the reference before applying the operator. The comma operator does that for us in line (1). This operator evaluates the first operand and returns the result of evaluating the second operand. The evaluation always produces values, which means that references are resolved and function names are lost.
Indirectly evaluated code is always sloppy. That is a consequence of the code being evaluated independently of its current surroundings:
function
strictFunc
()
{
'use strict'
;
var
code
=
'(function () { return this }())'
;
var
result
=
eval
.
call
(
null
,
code
);
console
.
log
(
result
!==
undefined
);
// true, sloppy mode
}
Evaluating Code Using new Function()
The constructor Function()
has the signature:
new
Function
(
param1
,
...,
paramN
,
funcBody
)
It creates a function whose zero or more parameters have the names param1
, parem2
, and so on, and whose body is funcBody
; that is, the created function looks like this:
function
(
«
param1
»
,
...,
«
paramN
»
)
{
«
funcBody
»
}
Let’s use new Function()
to create a function f
that returns the sum of its parameters:
- > var f = new Function('x', 'y', 'return x+y');
- > f(3, 4)
- 7
Similar to indirect eval()
, new Function()
creates functions whose scope is global:[18]
var
x
=
'global'
;
function
strictFunc
()
{
'use strict'
;
var
x
=
'local'
;
var
f
=
new
Function
(
'return x'
);
console
.
log
(
f
());
// global
}
Such functions are also sloppy by default:
function
strictFunc
()
{
'use strict'
;
var
sl
=
new
Function
(
'return this'
);
console
.
log
(
sl
()
!==
undefined
);
// true, sloppy mode
var
st
=
new
Function
(
'"use strict"; return this'
);
console
.
log
(
st
()
===
undefined
);
// true, strict mode
}
eval() Versus new Function()
Normally, it is better to use new Function()
than eval()
in order to evaluate code: the function parameters provide a clear interface to the evaluated code and you don’t need the slightly awkward syntax of indirect eval()
to ensure that the evaluated code can access only global variables (in addition to its own).
Best Practices
You should avoid eval()
and new Function()
. Dynamically evaluating code is slow and a potential security risk. It also prevents most tools (such as IDEs) that use static analysis from considering the code.
Often, there are better alternatives. For example, Brendan Eich recently tweeted an antipattern used by programmers who want to access a property whose name is stored in a variable propName
:
var
value
=
eval
(
'obj.'
+
propName
);
The idea makes sense: the dot operator only supports fixed, statically provided property keys. In this case, the property key is only known at runtime, which is why eval()
is needed in order to use that operator. Luckily, JavaScript also has the bracket operator, which does accept dynamic property keys. Therefore, the following is a better version of the preceding code:
var
value
=
obj
[
propName
];
You also shouldn’t use eval()
or new Function()
to parse JSON data. That is unsafe. Either rely on ECMAScript 5’s built-in support for JSON (see Chapter 22) or use a library.
Legitimate use cases
There are a few legitimate, albeit advanced, use cases for eval()
and new Function()
: configuration data with functions (which JSON does not allow), template libraries, interpreters, command lines, and module systems.
Conclusion
This was a relatively high-level overview of dynamically evaluating code in JavaScript. If you want to dig deeper, you can take a look at the article “Global eval. What are the options?” by kangax.
The Console API
This section provides an overview of the console API. It documents the status quo as of Chrome 32, Firebug 1.12, Firefox 25, Internet Explorer 11, Node.js 0.10.22, and Safari 7.0.
How Standardized Is the Console API Across Engines?
The implementations of the console API vary greatly and are constantly changing. If you want authoritative documentation, you have two options. First, you can look at standard-like overviews of the API:
- Firebug first implemented the console API, and the documentation in its wiki is the closest thing to a standard there currently is.
- Additionally, Brian Kardell and Paul Irish are working on a specification for the API, which should lead to more consistent behavior.
Second, you can look at the documentation of various engines:
Warning
There is a bug in Internet Explorer 9. In that browser, the console
object exists only if the developer tools were open at least once. That means that you get a ReferenceError
if you refer to console
and the tools weren’t open before. As a workaround, you can check whether console
exists and create a dummy implementation if it doesn’t.
Simple Logging
The console API includes the following logging methods:
console.clear()
- Clear the console.
console.debug(object1, object2?, …)
- Prefer
console.log()
, which does the same as this method. console.error(object1, object2?, …)
- Log the parameters to the console. In browsers, the logged content may be marked by an “error” icon and/or include a stack trace or a link to the code.
console.exception(errorObject, object1?, …])
[Firebug-only]- Log
object1
etc. and show an interactive stack trace. console.info(object1?, object2?, …)
- Log the parameters to the console. In browsers, the logged content may be marked by an “info” icon and/or include a stack trace or a link to the code.
console.log(object1?, object2?, …)
- Log the parameters to the console. If the first parameter is a
printf
-style format string, use it to print the remaining parameters. For example (Node.js REPL):
- > console.log('%s', { foo: 'bar' })
- [object Object]
- > console.log('%j', { foo: 'bar' })
- {"foo":"bar"}
The only dependable cross-platform formatting directive is %s
. Node.js supports %j
to format data as JSON; browsers tend to support directives that log something interactive to the console.
console.trace()
- Logs a stack trace (which is interactive in many browsers).
console.warn(object1?, object2?, …)
- Log the parameters to the console. In browsers, the logged content may be marked by a “warning” icon and/or include a stack trace or a link to the code.
Support on various platforms is indicated in the following table:
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
clear
| ✓ | ✓ | ✓ | ✓ | ||
debug
| ✓ | ✓ | ✓ | ✓ | ✓ | |
error
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
exception
| ✓ | |||||
info
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
log
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
trace
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
warn
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
exception
has been typeset in italics, because it is supported only on a single platform.
Checking and Counting
The console API includes the following checking and counting methods:
console.assert(expr, obj?)
- If
expr
isfalse
, logobj
to the console and throw an exception. If it istrue
, do nothing. console.count(label?)
- Count how many times the line with this statement is executed with this label.
Support on various platforms is indicated in the following table:
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
assert
| ✓ | ✓ | ✓ | ✓ | ✓ | |
count
| ✓ | ✓ | ✓ | ✓ |
Formatted Logging
The console API includes the following methods for formatted logging:
console.dir(object)
- Print a representation of the object to the console. In browsers, that representation can be explored interactively.
console.dirxml(object)
- Print the XML source tree of an HTML or XML element.
console.group(object1?, object2?, …)
- Log the objects to the console and open a nested block that contains all future logged content. Close the block by calling
console.groupEnd()
. The block is initially expanded, but can be collapsed. console.groupCollapsed(object1?, object2?, …)
- Works like
console.group()
, but the block is initially collapsed. console.groupEnd()
- Close a group that has been opened by
console.group()
orconsole.group
Collapsed()
. console.table(data, columns?)
- Print an array as a table, one element per row. The optional parameter
columns
specifies which properties/array indices are shown in the columns. If that parameter is missing, all property keys are used as table columns. Missing properties and array elements show up asundefined
in columns:
var
persons
=
[
{
firstName
:
'Jane'
,
lastName
:
'Bond'
},
{
firstName
:
'Lars'
,
lastName
:
'Croft'
,
age
:
72
}
];
// Equivalent:
console
.
table
(
persons
);
console
.
table
(
persons
,
[
'firstName'
,
'lastName'
,
'age'
]);
The resulting table is as follows:
(index) | firstName | lastName | age |
0 | “Jane” | “Bond” | undefined |
1 | “Lars” | “Croft” | 72 |
Support on various platforms is indicated in the following table:
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
dir
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
dirxml
| ✓ | ✓ | ✓ | ✓ | ||
group
| ✓ | ✓ | ✓ | ✓ | ✓ | |
groupCollapsed
| ✓ | ✓ | ✓ | ✓ | ✓ | |
groupEnd
| ✓ | ✓ | ✓ | ✓ | ✓ | |
table
| ✓ | ✓ |
Profiling and Timing
The console API includes the following methods for profiling and timing:
console.markTimeline(label)
[Safari-only]- The same as
console.timeStamp
. console.profile(title?)
- Turn on profiling. The optional
title
is used for the profile report. console.profileEnd()
- Stop profiling and print the profile report.
console.time(label)
- Start a timer whose label is
label
. console.timeEnd(label)
- Stop the timer whose label is
label
and print the time that has elapsed since starting it. console.timeStamp(label?)
- Log a timestamp with the given
label
. May be logged to the console or a timeline.
Support on various platforms is indicated in the following table:
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
markTimeline
| ✓ | |||||
profile
| ✓ | ✓ | (devtools) | ✓ | ✓ | |
profileEnd
| ✓ | ✓ | (devtools) | ✓ | ✓ | |
time
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
timeEnd
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
timeStamp
| ✓ | ✓ |
markTimeline
has been typeset in italics, because it is supported only on a single platform. The(devtools) designation means that the developer tools must be open in order for the method to work.[19]
Namespaces and Special Values
The following global variables serve as namespaces for functions. For details, see the material indicated in parentheses:
JSON
- JSON API functionality (Chapter 22)
Math
- Math API functionality (Chapter 21)
Object
- Metaprogramming functionality (Cheat Sheet: Working with Objects)
The following global variables contain special values. For more on them, review the material indicated in parentheses:
undefined
- A value expressing that something does not exist (undefined and null):
- > ({}.foo) === undefined
- true
NaN
- A value expressing that something is “not a number” (NaN):
- > 1 / 'abc'
- NaN
Infinity
- A value denoting numeric infinity ∞ (Infinity):
- > 1 / 0
- Infinity
[18] Mariusz Nowak (@medikoo) told me that code evaluated by Function
is sloppy by default, everywhere.
[19] Thanks to Matthias Reuter (@gweax) and Philipp Kyeck (@pkyeck), who contributed to this section.