本章是 ECMAScript 规范标准化的全局变量的参考。Web 浏览器拥有更多全局变量,这些变量在 MDN 上列出。所有全局变量都是全局对象(浏览器中的 window
;请参阅全局对象)的(自身或继承的)属性。
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
encodeURI(uri)
对 uri
中的特殊字符进行百分比编码。特殊字符是除以下字符之外的所有 Unicode 字符
URI 字符 |
|
也不编码 |
|
例如
> encodeURI('http://example.com/Für Elise/') 'http://example.com/F%C3%BCr%20Elise/'
encodeURIComponent(uriComponent)
对 uriComponent
中的所有字符进行百分比编码,但以下字符除外
不编码 |
|
与 encodeURI
相反,在 URL 和文件名中具有重要意义的字符也会被编码。因此,您可以使用此函数将任何文本转换为合法的文件名或 URL 路径段。例如
> encodeURIComponent('http://example.com/Für Elise/') 'http%3A%2F%2Fexample.com%2FF%C3%BCr%20Elise%2F'
decodeURI(encodedURI)
解码由 encodeURI
生成的百分比编码的 URI
> decodeURI('http://example.com/F%C3%BCr%20Elise/') 'http://example.com/Für Elise/'
encodeURI
不会对 URI 字符进行编码,decodeURI
也不会对其进行解码,即使它们已被正确编码
> decodeURI('%2F') '%2F' > decodeURIComponent('%2F') '/'
decodeURIComponent(encodedURIComponent)
解码由 encodeURIComponent
生成的百分比编码的 URI 组件。与 decodeURI
相反,所有百分比编码的字符都会被解码
> decodeURIComponent('http%3A%2F%2Fexample.com%2FF%C3%BCr%20Elise%2F') 'http://example.com/Für Elise/'
以下内容已弃用
escape(str)
对 str
进行百分比编码。它已被弃用,因为它无法正确处理非 ASCII 字符。请改用 encodeURIComponent()
。unescape(str)
对 str
进行百分比解码。它已被弃用,因为它无法正确处理非 ASCII 字符。请改用 decodeURIComponent()
。以下方法有助于对数字进行分类和解析:
isFinite(number)
(检查无穷大)isNaN(value)
(陷阱:检查值是否为 NaN)parseFloat(string)
(parseFloat())parseInt(string, radix)
(通过 parseInt() 获取整数)函数调用:
eval
(
str
)
评估 str
中的 JavaScript 代码。例如
> var a = 12; > eval('a + 5') 17
请注意,eval()
在语句上下文中进行解析(请参阅表达式与语句)
> eval('{ foo: 123 }') // code block 123 > eval('({ foo: 123 })') // object literal { foo: 123 }
对于 eval()
,您真的应该使用严格模式(请参阅严格模式)。在非严格模式下,评估的代码可以在周围作用域中创建局部变量
function
sloppyFunc
()
{
eval
(
'var foo = 123'
);
// added to the scope of sloppyFunc
console
.
log
(
foo
);
// 123
}
这在严格模式下不会发生
function
strictFunc
()
{
'use strict'
;
eval
(
'var foo = 123'
);
console
.
log
(
foo
);
// ReferenceError: foo is not defined
}
但是,即使在严格模式下,评估的代码仍然可以读取和写入周围作用域中的变量。要防止此类访问,您需要间接调用 eval()
。
call()
,作为 window
的方法,将其存储在不同的名称下并在那里调用,等等)。正如我们已经看到的,直接 eval()
在当前作用域中执行代码
var
x
=
'global'
;
function
directEval
()
{
'use strict'
;
var
x
=
'local'
;
console
.
log
(
eval
(
'x'
));
// local
}
相反,间接 eval()
在全局作用域中执行代码
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
}
(1)的解释:当您通过变量的名称引用它时,初始结果是一个所谓的引用,它是一个具有两个主要字段的数据结构
base
指向环境,即存储变量值的数据结构。referencedName
是变量的名称。在 eval()
函数调用期间,函数调用运算符(括号)遇到对 eval
的引用,并且可以确定要调用的函数的名称。因此,此类函数调用会触发直接 eval()
。但是,您可以通过不向调用运算符提供引用来强制执行间接 eval()
。这是通过在应用运算符之前检索引用的值来实现的。逗号运算符为我们完成了这一操作(第 1 行)。此运算符评估第一个操作数并返回评估第二个操作数的结果。评估始终会产生值,这意味着引用已解析并且函数名称丢失。
间接评估的代码始终是非严格的。这是代码独立于其当前环境进行评估的结果
function
strictFunc
()
{
'use strict'
;
var
code
=
'(function () { return this }())'
;
var
result
=
eval
.
call
(
null
,
code
);
console
.
log
(
result
!==
undefined
);
// true, sloppy mode
}
new
Function
(
param1
,
...,
paramN
,
funcBody
)
它创建一个函数,其零个或多个参数的名称为 param1
、parem2
等,其主体为 funcBody
;也就是说,创建的函数如下所示
function
(
«
param1
»
,
...,
«
paramN
»
)
{
«
funcBody
»
}
让我们使用 new Function()
创建一个函数 f
,该函数返回其参数的总和
> var f = new Function('x', 'y', 'return x+y'); > f(3, 4) 7
与间接 eval()
类似,new Function()
创建的作用域为全局的函数:[18]
var
x
=
'global'
;
function
strictFunc
()
{
'use strict'
;
var
x
=
'local'
;
var
f
=
new
Function
(
'return x'
);
console
.
log
(
f
());
// global
}
默认情况下,此类函数也是非严格的
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
}
通常,最好使用 new Function()
而不是 eval()
来评估代码:函数参数为评估的代码提供了一个清晰的接口,并且您不需要间接 eval()
的略显笨拙的语法来确保评估的代码只能访问全局变量(以及它自己的变量)。
您应该避免使用 eval()
和 new Function()
。动态评估代码速度慢且存在潜在的安全风险。它还会阻止大多数使用静态分析的工具(例如 IDE)考虑代码。
通常,有更好的选择。例如,Brendan Eich 最近在推特上发布了一种反模式,该模式由希望访问其名称存储在变量 propName
中的属性的程序员使用
var
value
=
eval
(
'obj.'
+
propName
);
这个想法是有道理的:点运算符仅支持固定的、静态提供的属性键。在这种情况下,属性键仅在运行时才知道,这就是为什么需要 eval()
来使用该运算符的原因。幸运的是,JavaScript 还具有括号运算符,它接受动态属性键。因此,以下是前面代码的更好版本
var
value
=
obj
[
propName
];
您也不应该使用 eval()
或 new Function()
来解析 JSON 数据。这是不安全的。请依赖 ECMAScript 5 对 JSON 的内置支持(请参阅第 22 章)或使用库。
eval()
和 new Function()
有一些合法但高级的用例:具有函数的配置数据(JSON 不允许)、模板库、解释器、命令行和模块系统。
这是对 JavaScript 中动态评估代码的相对高级的概述。如果您想深入了解,可以阅读 kangax 的文章“全局 eval。有哪些选择?”。
本节概述了控制台 API。它记录了截至 Chrome 32、Firebug 1.12、Firefox 25、Internet Explorer 11、Node.js 0.10.22 和 Safari 7.0 的现状。
控制台 API 的实现差异很大,并且在不断变化。如果您需要权威文档,则有两个选择。首先,您可以查看 API 的类标准概述:
其次,您可以查看各种引擎的文档
Internet Explorer 9 中存在一个错误。在该浏览器中,仅当开发人员工具至少打开过一次时,console
对象才存在。这意味着如果您引用 console
并且之前没有打开过该工具,则会收到 ReferenceError
。作为解决方法,您可以检查 console
是否存在,如果不存在则创建一个虚拟实现。
控制台 API 包括以下日志记录方法:
console.clear()
console.debug(object1, object2?, ...)
console.log()
,它的作用与此方法相同。console.error(object1, object2?, ...)
console.exception(errorObject, object1?, ...])
[仅限 Firebug]object1
等并显示交互式堆栈跟踪。console.info(object1?, object2?, ...)
console.log(object1?, object2?, ...)
将参数记录到控制台。如果第一个参数是 printf
风格的格式字符串,则使用它来打印剩余的参数。例如(Node.js REPL)
> console.log('%s', { foo: 'bar' }) [object Object] > console.log('%j', { foo: 'bar' }) {"foo":"bar"}
唯一可靠的跨平台格式指令是 %s
。Node.js 支持 %j
将数据格式化为 JSON;浏览器倾向于支持将交互式内容记录到控制台的指令。
console.trace()
console.warn(object1?, object2?, ...)
下表显示了在各种平台上的支持情况
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
| ✓ | ✓ | ✓ | ✓ | ||
| ✓ | ✓ | ✓ | ✓ | ✓ | |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | |||||
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
exception
已被设置为斜体,因为它仅在一个平台上受支持。
控制台 API 包括以下 检查和计数方法:
console.assert(expr, obj?)
expr
为 false
,则将 obj
记录到控制台并抛出异常。如果为 true
,则不执行任何操作。console.count(label?)
下表显示了在各种平台上的支持情况
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
| ✓ | ✓ | ✓ | ✓ | ✓ | |
| ✓ | ✓ | ✓ | ✓ |
控制台 API 包括以下用于格式化日志记录的方法
console.dir(object)
console.dirxml(object)
console.group(object1?, object2?, ...)
console.groupEnd()
关闭该块。该块最初是展开的,但可以折叠。console.groupCollapsed(object1?, object2?, ...)
console.group()
的工作方式类似,但该块最初是折叠的。console.groupEnd()
console.group()
或 console.group
Collapsed()
打开的组。console.table(data, columns?)
将数组打印为表格,每行一个元素。可选参数 columns
指定在列中显示哪些属性/数组索引。如果缺少该参数,则所有属性键都将用作表列。缺少的属性和数组元素在列中显示为 undefined
var
persons
=
[
{
firstName
:
'Jane'
,
lastName
:
'Bond'
},
{
firstName
:
'Lars'
,
lastName
:
'Croft'
,
age
:
72
}
];
// Equivalent:
console
.
table
(
persons
);
console
.
table
(
persons
,
[
'firstName'
,
'lastName'
,
'age'
]);
生成的表如下
(索引) | firstName | lastName | age |
0 | “Jane” | “Bond” | undefined |
1 | “Lars” | “Croft” | 72 |
下表显示了在各种平台上的支持情况
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ | ✓ | ✓ | ||
| ✓ | ✓ | ✓ | ✓ | ✓ | |
| ✓ | ✓ | ✓ | ✓ | ✓ | |
| ✓ | ✓ | ✓ | ✓ | ✓ | |
| ✓ | ✓ |
控制台 API 包括以下用于性能分析和计时的方法:
console.markTimeline(label)
[仅限 Safari]console.timeStamp
相同。console.profile(title?)
title
用于性能分析报告。console.profileEnd()
console.time(label)
label
的计时器。console.timeEnd(label)
label
的计时器,并打印自启动以来经过的时间。console.timeStamp(label?)
label
的时间戳。可以记录到控制台或时间线。下表显示了在各种平台上的支持情况
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
| ✓ | |||||
| ✓ | ✓ | (开发者工具) | ✓ | ✓ | |
| ✓ | ✓ | (开发者工具) | ✓ | ✓ | |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ |
markTimeline
已被设置为斜体,因为它仅在一个平台上受支持。(开发者工具)表示必须打开开发者工具才能使该方法正常工作。[19]
以下全局变量用作函数的命名空间。有关详细信息,请参阅括号中指示的材料:
以下全局变量包含特殊值。有关它们的更多信息,请查看括号中指示的材料:
undefined
> ({}.foo) === undefined true
NaN
> 1 / 'abc' NaN
Infinity
> 1 / 0 Infinity