本章是 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(),您真的应该使用严格模式(请参阅严格模式)。在非严格模式下,评估的代码可以在周围作用域中创建局部变量
functionsloppyFunc(){eval('var foo = 123');// added to the scope of sloppyFuncconsole.log(foo);// 123}
这在严格模式下不会发生
functionstrictFunc(){'use strict';eval('var foo = 123');console.log(foo);// ReferenceError: foo is not defined}
但是,即使在严格模式下,评估的代码仍然可以读取和写入周围作用域中的变量。要防止此类访问,您需要间接调用 eval()。
call(),作为 window 的方法,将其存储在不同的名称下并在那里调用,等等)。正如我们已经看到的,直接 eval() 在当前作用域中执行代码
varx='global';functiondirectEval(){'use strict';varx='local';console.log(eval('x'));// local}
相反,间接 eval() 在全局作用域中执行代码
varx='global';functionindirectEval(){'use strict';varx='local';// Don’t call eval directlyconsole.log(eval.call(null,'x'));// globalconsole.log(window.eval('x'));// globalconsole.log((1,eval)('x'));// global (1)// Change the name of evalvarxeval=eval;console.log(xeval('x'));// global// Turn eval into a methodvarobj={eval:eval};console.log(obj.eval('x'));// global}
(1)的解释:当您通过变量的名称引用它时,初始结果是一个所谓的引用,它是一个具有两个主要字段的数据结构
base 指向环境,即存储变量值的数据结构。referencedName 是变量的名称。在 eval() 函数调用期间,函数调用运算符(括号)遇到对 eval 的引用,并且可以确定要调用的函数的名称。因此,此类函数调用会触发直接 eval()。但是,您可以通过不向调用运算符提供引用来强制执行间接 eval()。这是通过在应用运算符之前检索引用的值来实现的。逗号运算符为我们完成了这一操作(第 1 行)。此运算符评估第一个操作数并返回评估第二个操作数的结果。评估始终会产生值,这意味着引用已解析并且函数名称丢失。
间接评估的代码始终是非严格的。这是代码独立于其当前环境进行评估的结果
functionstrictFunc(){'use strict';varcode='(function () { return this }())';varresult=eval.call(null,code);console.log(result!==undefined);// true, sloppy mode}
newFunction(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]
varx='global';functionstrictFunc(){'use strict';varx='local';varf=newFunction('return x');console.log(f());// global}
默认情况下,此类函数也是非严格的
functionstrictFunc(){'use strict';varsl=newFunction('return this');console.log(sl()!==undefined);// true, sloppy modevarst=newFunction('"use strict"; return this');console.log(st()===undefined);// true, strict mode}
通常,最好使用 new Function() 而不是 eval() 来评估代码:函数参数为评估的代码提供了一个清晰的接口,并且您不需要间接 eval() 的略显笨拙的语法来确保评估的代码只能访问全局变量(以及它自己的变量)。
您应该避免使用 eval() 和 new Function()。动态评估代码速度慢且存在潜在的安全风险。它还会阻止大多数使用静态分析的工具(例如 IDE)考虑代码。
通常,有更好的选择。例如,Brendan Eich 最近在推特上发布了一种反模式,该模式由希望访问其名称存储在变量 propName 中的属性的程序员使用
varvalue=eval('obj.'+propName);
这个想法是有道理的:点运算符仅支持固定的、静态提供的属性键。在这种情况下,属性键仅在运行时才知道,这就是为什么需要 eval() 来使用该运算符的原因。幸运的是,JavaScript 还具有括号运算符,它接受动态属性键。因此,以下是前面代码的更好版本
varvalue=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
varpersons=[{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
trueNaN
> 1 / 'abc' NaN
Infinity
> 1 / 0 Infinity