大话 JavaScript(Speaking JavaScript):第二十一章到第二十五章

第二十一章:数学

原文:21. Math

译者:飞龙

协议:CC BY-NC-SA 4.0

Math对象用作多个数学函数的命名空间。本章提供了一个概述。

数学属性

Math的属性如下:

Math.E

欧拉常数(e)

Math.LN2

2 的自然对数

Math.LN10

10 的自然对数

Math.LOG2E

e 的底数 2 对数

Math.LOG10E

e 的十进制对数

Math.PI

圆的周长与直径的比值(3.14159 …),π

Math.SQRT1_2

一半的平方根,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Math.SQRT2

二的平方根,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数值函数

Math的数值函数包括以下内容:

Math.abs(x)

返回x的绝对值。

Math.ceil(x)

返回大于等于x的最小整数:

> Math.ceil(3.999)
4
> Math.ceil(3.001)
4
> Math.ceil(-3.001)
-3
> Math.ceil(3.000)
3

有关将浮点数转换为整数的更多信息,请参阅转换为整数。

Math.exp(x)

返回 e^x,其中 e 是欧拉常数(Math.E)。这是Math.log()的反函数。

Math.floor(x)

返回小于等于x的最大整数:

> Math.floor(3.999)
3
> Math.floor(3.001)
3
> Math.floor(-3.001)
-4
> Math.floor(3.000)
3

有关将浮点数转换为整数的更多信息,请参阅转换为整数。

Math.log(x)

返回x的自然(以 e 为底)对数 ln(x)。这是Math.exp()的反函数。

Math.pow(x, y)

返回 x^y,xy次幂:

> Math.pow(9, 2)
81
> Math.pow(36, 0.5)
6

Math.round(x)

返回x四舍五入到最接近的整数(如果在两个整数之间,则为较大的整数):

> Math.round(3.999)
4
> Math.round(3.001)
3
> Math.round(3.5)
4
> Math.round(-3.5)
-3

有关将浮点数转换为整数的更多信息,请参阅转换为整数。

Math.sqrt(x)

返回外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传x的平方根:

> Math.sqrt(256)
16

三角函数

三角函数方法接受弧度作为角度并返回。以下函数向您展示了如何实现转换,如果需要的话:

  • 从度到弧度:

    function toRadians(degrees) {return degrees / 180 * Math.PI;
    }
    

以下是交互:

    > toRadians(180)3.141592653589793> toRadians(90)1.5707963267948966```+   从弧度到度:```jsfunction toDegrees(radians) {return radians / Math.PI * 180;}```以下是交互:```js> toDegrees(Math.PI * 2)360> toDegrees(Math.PI)180```三角函数方法如下:`Math.acos(x)`返回`x`的反余弦值。`Math.asin(x)`返回`x`的反正弦值。`Math.atan(x)`返回`x`的反正切值。`Math.atan2(y, x)`返回商的反正切值![](inleq_2104.png)。`Math.cos(x)`返回`x`的余弦值。`Math.sin(x)`返回`x`的正弦值。`Math.tan(x)`返回`x`的正切值。## 其他函数以下是剩余的`Math`函数:`min(x1?, x2?, ...)`返回参数中的最小数:```js
> Math.min()
Infinity
> Math.min(27)
27
> Math.min(27, -38)
-38
> Math.min(27, -38, -43)
-43

通过apply()在数组上使用它(参见func.apply(thisValue, argArray)):

> Math.min.apply(null, [27, -38, -43])
-43

max(x1?, x2?, ...)

返回参数中的最大数:

> Math.max()
-Infinity
> Math.max(7)
7
> Math.max(7, 10)
10
> Math.max(7, 10, -333)
10

通过apply()在数组上使用它(参见func.apply(thisValue, argArray)):

> Math.max.apply(null, [7, 10, -333])
10

Math.random()

/*** Compute a random integer within the given range.** @param [lower] Optional lower bound. Default: zero.* @returns A random integer i, lower ≤ i < upper*/
function getRandomInteger(lower, upper) {if (arguments.length === 1) {upper = lower;lower = 0;}return Math.floor(Math.random() * (upper - lower)) + lower;
}

第二十二章:JSON

原文:22. JSON

译者:飞龙

协议:CC BY-NC-SA 4.0

JSON(JavaScript 对象表示)是一种用于数据存储的纯文本格式。它已经成为 Web 服务、配置文件等数据交换格式的一种流行选择。ECMAScript 5 有一个 API,用于将 JSON 格式的字符串转换为 JavaScript 值(解析)以及反之(字符串化)。

背景

本节解释了 JSON 是什么以及它是如何创建的。

数据格式

JSON 将数据存储为纯文本。它的语法是 JavaScript 表达式语法的子集。例如:

{"first": "Jane","last": "Porter","married": true,"born": 1890,"friends": [ "Tarzan", "Cheeta" ]
}

JSON 使用 JavaScript 表达式中的以下结构:

复合

JSON 数据的对象和 JSON 数据的数组

原子

字符串、数字、布尔值和空值

它遵循以下规则:

  • 字符串必须始终用双引号括起来;例如,像'mystr'这样的字符串字面量是非法的。

  • 属性键必须用双引号括起来

历史

Douglas Crockford 于 2001 年发现了 JSON。他给它起了个名字,并在json.org上发布了一个规范:

我发现了 JSON。我不主张发明 JSON,因为它已经存在于自然界中。我所做的是发现它,我给它起了名字,我描述了它的有用之处。我不主张自己是第一个发现它的人;我知道至少有其他人在我之前至少一年发现了它。我发现的最早的情况是,Netscape 有人在至少 1996 年就开始使用 JavaScript 数组文字进行数据通信,而这至少比我想到这个想法早了五年。

最初,Crockford 希望 JSON 有一个名字叫JavaScript 标记语言,但是 JSML 的首字母缩写已经被JSpeech 标记语言使用了。

JSON 规范已经被翻译成许多人类语言,现在有许多编程语言的库支持解析和生成 JSON。

语法

Douglas Crockford 创建了一张 JSON 名片,正面有一个徽标(参见图 22-1),背面有完整的语法(参见图 22-2)。这使得 JSON 的简单性在视觉上显而易见。

JSON 名片的正面显示了一个徽标(来源:Eric Miraglia)。图 22-1:JSON 名片的正面显示了一个徽标(来源:Eric Miraglia)。

JSON 名片的背面包含完整的语法(来源:Eric Miraglia)。图 22-2:JSON 名片的背面包含完整的语法(来源:Eric Miraglia)。

语法可以转录如下:

object{ }{ members }memberspairpair , memberspairstring : valuearray[ ][ elements ]elementsvaluevalue , elementsvaluestringnumberobjectarraytruefalsenullstring""" chars "charscharchar charscharany-Unicode-character-except-"-or-\-or-control-character\" \\ \/ \b \f \n \r \t\u four-hex-digitsnumberintint fracint expint frac expintdigitdigit1-9 digits- digit- digit1-9 digitsfrac. digitsexpe digitsdigitsdigitdigit digitsee e+ e-E E+ E-

全局变量JSON用作生成和解析带有 JSON 数据的字符串的函数的命名空间。

JSON.stringify(value, replacer?, space?)

JSON.stringify(value, replacer?, space?)将 JavaScript 值value转换为 JSON 格式的字符串。它有两个可选参数。

可选参数replacer用于在对其进行字符串化之前更改value。它可以是:

  • 一个节点访问者(参见通过节点访问者转换数据)在将其字符串化之前转换值树。例如:

    function replacer(key, value) {if (typeof value === 'number') {value = 2 * value;}return value;
    }
    

使用 replacer:

    > JSON.stringify({ a: 5, b: [ 2, 8 ] }, replacer)'{"a":10,"b":[4,16]}'```+   隐藏所有不在列表中的属性键(非数组对象的属性)的属性白名单。例如:```js> JSON.stringify({foo: 1, bar: {foo: 1, bar: 1}}, ['bar'])'{"bar":{"bar":1}}'```白名单对数组没有影响:```js> JSON.stringify(['a', 'b'], ['0'])'["a","b"]'```可选参数`space`影响输出的格式。如果没有这个参数,`stringify`的结果将是单行文本:```js
> console.log(JSON.stringify({a: 0, b: ['\n']}))
{"a":0,"b":["\n"]}

使用它,可以插入换行符,并且通过数组和对象的每个嵌套级别增加缩进。有两种指定缩进方式的方法:

一个数字

将数字乘以缩进级别并将行缩进为相同数量的空格。小于 0 的数字被解释为 0;大于 10 的数字被解释为 10:

> console.log(JSON.stringify({a: 0, b: ['\n']}, null, 2))
{"a": 0,"b": ["\n"]
}

一个字符串

要缩进,重复给定的字符串以表示每个缩进级别。只使用字符串的前 10 个字符:

> console.log(JSON.stringify({a: 0, b: ['\n']}, null, '|--'))
{
|--"a": 0,
|--"b": [
|--|--"\n"
|--]
}

因此,以下对JSON.stringify()的调用会将对象打印为一个格式良好的树:

JSON.stringify(data, null, 4)

JSON.stringify()忽略的数据

在对象中,JSON.stringify()只考虑可枚举的自有属性(参见属性特性和属性描述符)。以下示例演示了忽略了不可枚举的自有属性obj.foo

> var obj = Object.defineProperty({}, 'foo', { enumerable: false, value: 7 });
> Object.getOwnPropertyNames(obj)
[ 'foo' ]
> obj.foo
7
> JSON.stringify(obj)
'{}'

JSON.stringify()处理不受 JSON 支持的值(例如函数和undefined)的方式取决于它们遇到的位置。不支持的值本身导致stringify()返回undefined而不是字符串:

> JSON.stringify(function () {})
undefined

其值不受支持的属性将被简单地忽略:

> JSON.stringify({ foo: function () {} })
'{}'

数组中不支持的值将被字符串化为null

> JSON.stringify([ function () {} ])
'[null]'

toJSON()方法

如果JSON.stringify()遇到具有toJSON方法的对象,则使用该方法获取要字符串化的值。例如:

> JSON.stringify({ toJSON: function () { return 'Cool' } })
'"Cool"'

日期已经有一个产生 ISO 8601 日期字符串的toJSON方法:

> JSON.stringify(new Date('2011-07-29'))
'"2011-07-28T22:00:00.000Z"'

toJSON方法的完整签名如下:

function (key)

key参数允许您根据上下文以不同方式进行字符串化。它始终是一个字符串,并指示在父对象中找到您的对象的位置:

根位置

空字符串

属性值

属性键

数组元素

元素的索引作为字符串

我将通过以下对象演示toJSON()

var obj = {toJSON: function (key) {// Use JSON.stringify for nicer-looking outputconsole.log(JSON.stringify(key));return 0;}
};

如果使用JSON.stringify(),则每次出现obj都会被替换为0。通知toJSON()方法在属性键'foo'和数组索引 0 处遇到了obj

> JSON.stringify({ foo: obj, bar: [ obj ]})
"foo"
"0"
'{"foo":0,"bar":[0]}'

内置的toJSON()方法如下:

  • Boolean.prototype.toJSON()

  • Number.prototype.toJSON()

  • String.prototype.toJSON()

  • Date.prototype.toJSON()

JSON.parse(text, reviver?)

JSON.parse(text, reviver?)解析text中的 JSON 数据并返回 JavaScript 值。以下是一些示例:

> JSON.parse("'String'") // illegal quotes
SyntaxError: Unexpected token ILLEGAL
> JSON.parse('"String"')
'String'
> JSON.parse('123')
123
> JSON.parse('[1, 2, 3]')
[ 1, 2, 3 ]
> JSON.parse('{ "hello": 123, "world": 456 }')
{ hello: 123, world: 456 }

可选参数reviver是一个节点访问者(参见通过节点访问者转换数据),可用于转换解析后的数据。在此示例中,我们将日期字符串转换为日期对象:

function dateReviver(key, value) {if (typeof value === 'string') {var x = Date.parse(value);if (!isNaN(x)) { // valid date string?return new Date(x);}}return value;
}

以下是交互:

> var str = '{ "name": "John", "birth": "2011-07-28T22:00:00.000Z" }';
> JSON.parse(str, dateReviver)
{ name: 'John', birth: Thu, 28 Jul 2011 22:00:00 GMT }

通过节点访问者转换数据

JSON.stringify()JSON.parse()都允许您通过传递函数来转换 JavaScript 数据:

  • JSON.stringify()允许您在将其转换为 JSON 之前更改 JavaScript 数据。

  • JSON.parse()解析 JSON,然后让您对生成的 JavaScript 数据进行后处理。

JavaScript 数据是一个树,其复合节点是数组和对象,其叶子是原始值(布尔值,数字,字符串,null)。让我们将传递的转换函数称为节点访问者。这些方法遍历树并为每个节点调用访问者。然后可以选择替换或删除节点。节点访问者的签名如下:

function nodeVisitor(key, value)

参数是:

this

当前节点的父节点。

key

当前节点位于其父节点内的键。key 总是一个字符串。

当前节点。

根节点 root 没有父节点。当访问 root 时,为其创建了一个伪父节点,并且参数具有以下值:

  • this{ '': root }

  • key''

  • valueroot

节点访问者有三种返回值的选项:

  • 返回 value,然后不执行任何更改。

  • 返回不同的值。然后当前节点被替换。

  • 返回 undefined。然后移除节点。

以下是节点访问者的示例。它记录了传递给它的值。

function nodeVisitor(key, value) {console.log([// Use JSON.stringify for nicer-looking outputJSON.stringify(this), // parentJSON.stringify(key),JSON.stringify(value)].join(' # '));return value; // don't change node
}

让我们使用此函数来检查 JSON 方法如何迭代 JavaScript 数据。

JSON.stringify()

特殊的根节点首先出现在前缀迭代中(父节点在子节点之前)。访问的第一个节点始终是伪根。在每次调用后显示的最后一行是 stringify() 返回的字符串:

> JSON.stringify(['a','b'], nodeVisitor)
{"":["a","b"]} # "" # ["a","b"]
["a","b"] # "0" # "a"
["a","b"] # "1" # "b"
'["a","b"]'> JSON.stringify({a:1, b:2}, nodeVisitor)
{"":{"a":1,"b":2}} # "" # {"a":1,"b":2}
{"a":1,"b":2} # "a" # 1
{"a":1,"b":2} # "b" # 2
'{"a":1,"b":2}'> JSON.stringify('abc', nodeVisitor)
{"":"abc"} # "" # "abc"
'"abc"'

JSON.parse()

首先是叶子节点,在后缀迭代中(子节点在父节点之前)。访问的最后一个节点始终是伪根。在每次调用后显示的最后一行是 parse() 返回的 JavaScript 值:

> JSON.parse('["a","b"]', nodeVisitor)
["a","b"] # "0" # "a"
["a","b"] # "1" # "b"
{"":["a","b"]} # "" # ["a","b"]
[ 'a', 'b' ]> JSON.parse('{"a":1, "b":2}', nodeVisitor)
{"a":1,"b":2} # "a" # 1
{"a":1,"b":2} # "b" # 2
{"":{"a":1,"b":2}} # "" # {"a":1,"b":2}
{ a: 1, b: 2 }> JSON.parse('"hello"', nodeVisitor)
{"":"hello"} # "" # "hello"
'hello'

第二十三章:标准全局变量

原文:23. Standard Global Variables

译者:飞龙

协议:CC BY-NC-SA 4.0

本章是 ECMAScript 规范标准化的全局变量的参考。Web 浏览器有更多全局变量,这些变量在 MDN 上列出。所有全局变量都是全局对象的(自有或继承的)属性(在浏览器中是 window;参见 全局对象)。

构造函数

有关以下构造函数的详细信息,请参见括号中指示的部分:

  • Array([数组构造函数](ch18.html#array_constructor “数组构造函数”))

  • Boolean([原始值的包装对象](ch08.html#wrapper_objects “原始值的包装对象”))

  • Date([日期构造函数](ch20.html#date_constructors “日期构造函数”))

  • Function([使用 new Function() 评估代码](ch23.html#function_constructor “使用 new Function() 评估代码”))

  • Number([原始值的包装对象](ch08.html#wrapper_objects “原始值的包装对象”))

  • 对象([将任何值转换为对象](ch17_split_000.html#toobject “将任何值转换为对象”))

  • RegExp([创建正则表达式](ch19.html#creating_regexps “创建正则表达式”))

  • String([原始值的包装对象](ch08.html#wrapper_objects “原始值的包装对象”))

错误构造函数

有关这些构造函数的详细信息,请参见 [错误构造函数](ch14.html#error_constructors “错误构造函数”):

  • Error

  • EvalError

  • RangeError

  • ReferenceError

  • SyntaxError

  • TypeError

  • URIError

非构造函数

有几个全局函数不是构造函数。它们在本节中列出。

编码和解码文本

以下函数处理 URI 编码和解码的几种方式:

encodeURI(uri)

uri 中对特殊字符进行百分比编码。特殊字符是除以下字符外的所有 Unicode 字符:

URI 字符:; , / ? : @ & = + $ #
未编码:a-z A-Z 0-9 - _ . ! ~ * ' ( )

例如:

> encodeURI('http://example.com/Für Elise/')
'http://example.com/F%C3%BCr%20Elise/'

encodeURIComponent(uriComponent)

uriComponent 中对所有字符进行百分比编码,除了:

| 未编码: | a-z A-Z 0-9 - _ . ! ~ * ' ( ) |

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()和 new Function()动态评估 JavaScript 代码

本节将介绍如何在 JavaScript 中动态评估代码。

使用 eval()评估代码

函数调用:

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()

对于eval(),您确实应该使用严格模式(参见严格模式)。在松散模式下,评估的代码可以在周围范围内创建局部变量:

function sloppyFunc() {eval('var foo = 123');  // added to the scope of sloppyFuncconsole.log(foo);  // 123
}

在严格模式下无法发生:

function strictFunc() {'use strict';eval('var foo = 123');console.log(foo);  // ReferenceError: foo is not defined
}

然而,即使在严格模式下,评估的代码仍然可以读取和写入周围范围内的变量。要防止这种访问,您需要间接调用eval()

间接 eval()在全局范围内进行评估

有两种调用eval()的方法:

  • 直接。通过直接调用名称为“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 directlyconsole.log(eval.call(null, 'x')); // globalconsole.log(window.eval('x')); // globalconsole.log((1, eval)('x')); // global (1)// Change the name of evalvar xeval = eval;console.log(xeval('x')); // global// Turn eval into a methodvar 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()评估代码

构造函数Function()的签名为:

new Function(param1, ..., paramN, funcBody)

它创建一个函数,其零个或多个参数的名称为param1parem2等,其主体为funcBody;也就是说,创建的函数如下所示:

function («param1», ..., «paramN») {«funcBody»
}

让我们使用new Function()创建一个函数f,它返回其参数的总和:

> var f = new Function('x', 'y', 'return x+y');
> f(3, 4)
7

类似于间接eval()new Function()创建其作用域为全局的函数:¹⁶

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 modevar st = new Function('"use strict"; return this');console.log(st() === undefined); // true, strict mode
}

eval()与 new Function()

通常,最好使用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 的内置支持(参见第二十二章),要么使用一个库。

合法的用例

eval()new Function()有一些合法的,尽管是高级的用例:带有函数的配置数据(JSON 不允许),模板库,解释器,命令行和模块系统。

结论

这是 JavaScript 动态评估代码的一个相对高级的概述。如果你想深入了解,可以查看 kangax 的文章“全局 eval。有哪些选项?”。

控制台 API

在大多数 JavaScript 引擎中,有一个全局对象console,其中包含用于记录和调试的方法。该对象不是语言本身的一部分,但已成为事实上的标准。由于它们的主要目的是调试,console方法在开发过程中最常用,而在部署的代码中很少使用。

本节概述了控制台 API。它记录了 Chrome 32、Firebug 1.12、Firefox 25、Internet Explorer 11、Node.js 0.10.22 和 Safari 7.0 的现状。

控制台 API 在各种引擎之间的标准化程度如何?

控制台 API 的实现差异很大,而且不断变化。如果你想要权威的文档,你有两个选择。首先,你可以查看 API 的标准概述:

  • Firebug 首先实现了控制台 API,其在其维基中的文档是目前最接近标准的东西。

  • 此外,Brian Kardell 和 Paul Irish 正在制定API 规范,这应该会导致更一致的行为。

其次,你可以查看各种引擎的文档:

  • Chrome

  • Firebug

  • Firefox

  • Internet Explorer

  • Node.js

  • Safari

警告

在 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?, ...)

将参数记录到控制台。在浏览器中,记录的内容可能会被“警告”图标标记,和/或包括堆栈跟踪或代码链接。

在以下表中指出了各种平台的支持:

ChromeFirebugFirefoxIENode.jsSafari
clear
debug
error
exception
info
log
trace
warn

exception以斜体排版,因为它只在单个平台上受支持。

检查和计数

控制台 API 包括以下检查和计数方法:

console.assert(expr, obj?)

如果exprfalse,则将obj记录到控制台并抛出异常。如果为true,则什么也不做。

console.count(label?)

计算带有此语句的行被执行的次数。

在以下表中指出了各种平台的支持:

ChromeFirebugFirefoxIENode.jsSafari
assert
count

格式化日志

控制台 API 包括以下格式化日志的方法:

console.dir(object)

将对象的表示打印到控制台。在浏览器中,该表示可以交互地进行探索。

console.dirxml(object)

打印 HTML 或 XML 元素的 XML 源树。

console.group(object1?, object2?, ...)

将对象记录到控制台并打开一个包含所有未来记录内容的嵌套块。通过调用console.groupEnd()来关闭该块。该块最初是展开的,但可以折叠。

console.groupCollapsed(object1?, object2?, ...)

类似于console.group(),但是该块最初是折叠的。

console.groupEnd()

关闭由console.group()console.groupCollapsed()打开的组。

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']);

结果表如下:

(索引)名字姓氏年龄
0“Jane”“Bond”undefined
1“Lars”“Croft”72

在以下表中指出了各种平台的支持:

ChromeFirebugFirefoxIENode.jsSafari
dir
dirxml
group
groupCollapsed
groupEnd
table

分析和计时

控制台 API 包括以下用于分析和计时的方法:

控制台.标记时间线(标签) [仅限 Safari]

console.timeStamp相同。

控制台.性能(标题?)

打开分析。可选的title用于分析报告。

控制台.分析结束()

停止分析并打印分析报告。

控制台.时间(标签)

启动标签为label的计时器。

控制台.时间结束(标签)

停止标签为label的计时器并打印自启动以来经过的时间。

控制台.时间戳(标签?)

记录具有给定label的时间戳。可以记录到控制台或时间轴。

以下表格显示了各种平台上的支持:

ChromeFirebugFirefoxIENode.jsSafari
markTimeline
profile(devtools)
profileEnd(devtools)
time
timeEnd
timeStamp

markTimeline以斜体排版,因为它仅在单个平台上受支持。 (devtools)表示必须打开开发人员工具才能使该方法起作用。¹⁷

命名空间和特殊值

以下全局变量用作函数的命名空间。有关详细信息,请参阅括号中指示的材料:

JSON

JSON API 功能([第二十二章](ch22.html “第二十二章.JSON”))

数学

数学 API 功能([第二十一章](ch21.html “第二十一章.数学”))

对象

元编程功能([对象操作小抄:使用对象](ch17_split_001.html#oop_cheat_sheet “对象操作小抄:使用对象”))

以下全局变量包含特殊值。有关更多信息,请查看括号中指示的材料:

未定义

表示某物不存在的值([未定义和 null](ch08.html#undefined_null “未定义和 null”):

> ({}.foo) === undefined
true

NaN

一个表示某物是“非数字”([NaN](ch11.html#nan “NaN”)的值:

> 1 / 'abc'
NaN

无穷大

表示数值无穷大∞的值([无穷大](ch11.html#infinity “无穷大”):

> 1 / 0
Infinity

¹⁶ Mariusz Nowak(@medikoo)告诉我,由Function评估的代码默认情况下在任何地方都是松散的。

¹⁷ 感谢 Matthias Reuter(@gweax)和 Philipp Kyeck(@pkyeck)对本节的贡献。

第二十四章: Unicode 和 JavaScript

原文:24. Unicode and JavaScript

译者:飞龙

协议:CC BY-NC-SA 4.0

本章是对 Unicode 及其在 JavaScript 中的处理的简要介绍。

Unicode 历史

Unicode 始于 1987 年,由 Joe Becker(施乐),Lee Collins(苹果)和 Mark Davis(苹果)发起。其想法是创建一个通用字符集,因为当时对于编码纯文本存在许多不兼容的标准:许多变体的 8 位 ASCII,Big Five(繁体中文),GB 2312(简体中文)等。在 Unicode 之前,没有多语言纯文本的标准,但有丰富的文本系统(例如苹果的 WorldScript),允许您组合多个编码。

第一份 Unicode 草案提案于 1988 年发布。此后继续工作并扩大工作组。Unicode 联盟于 1991 年 1 月 3 日成立:

Unicode 联盟是一家致力于开发、维护和推广软件国际化标准和数据的非营利性公司,特别是 Unicode 标准[…]

Unicode 1.0 标准的第一卷于 1991 年 10 月出版,第二卷于 1992 年 6 月出版。

重要的 Unicode 概念

字符的概念可能看起来很简单,但它有许多方面。这就是为什么 Unicode 是一个如此复杂的标准。以下是重要的基本概念:

字符和字形

这两个术语的意思相似。字符是数字实体,而字形是书面语言的原子单位(字母、印刷连字、中文字符、标点符号等)。程序员以字符为思考单位,而用户以字形为思考单位。有时需要使用多个字符来表示单个字形。例如,我们可以通过组合字符o和字符^(抑扬符)来产生单个字形ô。

字形

这是一种显示字形的具体方式。有时,相同的字形在不同的上下文或其他因素下显示方式不同。例如,字形fi可以呈现为字形f和字形i,通过连字字形连接,或者没有连字。

代码点

Unicode 通过称为代码点的数字来表示它支持的字符。代码点的十六进制范围是 0x0 到 0x10FFFF(17 倍 16 位)。

代码单元

为了存储或传输代码点,我们将它们编码为代码单元,这是具有固定长度的数据片段。长度以位为单位,并由编码方案确定,Unicode 有几种编码方案,例如 UTF-8 和 UTF-16。名称中的数字表示代码单元的长度,以位为单位。如果一个代码点太大而无法适应单个代码单元,它必须被分解为多个单元;也就是说,表示单个代码点所需的代码单元数量可能会有所不同。

BOM(字节顺序标记)

如果一个代码单元大于一个字节,字节顺序很重要。BOM 是文本开头的一个伪字符(可能被编码为多个代码单元),指示代码单元是大端(最重要的字节在前)还是小端(最不重要的字节在前)。没有 BOM 的文本的默认值是大端。BOM 还指示所使用的编码;对于 UTF-8、UTF-16 等编码是不同的。此外,如果 Web 浏览器没有关于文本编码的其他信息,它还可以作为 Unicode 的标记。然而,由于几个原因,BOM 并不经常使用:

  • UTF-8 是迄今为止最流行的 Unicode 编码,不需要 BOM,因为只有一种字节排序方式。

  • 几种字符编码规定了固定的字节顺序。那么就不应该使用 BOM。例如 UTF-16BE(UTF-16 大端)、UTF-16LE、UTF-32BE 和 UTF-32LE。这是处理字节顺序的更安全的方式,因为元数据和数据保持分开,不会混淆。

规范化

有时相同的字形可以用几种方式表示。例如,字形ö可以表示为单个代码点,也可以表示为一个o后跟一个组合字符¨(分音符,双点)。规范化是将文本转换为规范表示的过程;等效的代码点和代码点序列都被转换为相同的代码点(或代码点序列)。这对于文本处理(例如搜索文本)很有用。Unicode 规定了几种规范化。

字符属性

规范指定了规范的几个属性,其中一些列在这里:

  • 名称。一个由大写字母 A-Z,数字 0-9,连字符(-)和<空格>组成的英文名称。两个例子:

  • “λ”的名称是“希腊小写字母λ”。

  • “!”的名称是“感叹号”。

  • 一般类别。将字符分成字母、大写字母、数字和标点等类别。

  • 年龄。该字符是在哪个版本的 Unicode 中引入的(1.0、1.1、2.0 等)?

  • 已弃用。是否不鼓励使用该字符?

  • 以及更多

代码点

代码点的范围最初是 16 位。随着 Unicode 版本 2.0(1996 年 7 月)的扩展,它现在被分成了 17 个平面,编号从 0 到 16。每个平面包括 16 位(十六进制表示法:0x0000–0xFFFF)。因此,在接下来的十六进制范围中,四个底部以外的数字包含了平面的编号。

  • 第 0 平面,基本多文种平面(BMP):0x0000–0xFFFF

  • 第 1 平面,补充多语种平面(SMP):0x10000–0x1FFFF

  • 第 2 平面,补充表意文字平面(SIP):0x20000–0x2FFFF

  • 第 3–13 平面,未分配

  • 第 14 平面,补充特殊用途平面(SSP):0xE0000–0xEFFFF

  • 第 15–16 平面,补充专用区域(S PUA A/B):0x0F0000–0x10FFFF

第 1–16 平面称为补充平面星际平面

Unicode 编码

UTF-32(Unicode 转换格式 32)是一种具有 32 位代码单元的格式。任何代码点都可以由单个代码单元编码,使得这是唯一的固定长度编码;对于其他编码,编码一个点所需的单元数量是变化的。

UTF-16是一种具有 16 位代码单元的格式,需要一个到两个单元来表示一个代码点。BMP 代码点可以由单个代码单元表示。高代码点是 20 位(16 乘以 16 位),在减去 0x10000(BMP 的范围)后。这些位被编码为两个代码单元(所谓的代理对):

领先代理

最重要的 10 位:存储在范围 0xD800–0xDBFF 中。也称为高代理代码单元

尾随代理

最不重要的 10 位:存储在范围 0xDC00–0xDFFF 中。也称为低代理代码单元

以下表格(改编自 Unicode 标准 6.2.0,表 3-5)可视化了位的分布:

代码点UTF-16 代码单元
xxxxxxxxxxxxxxxx(16 位)xxxxxxxxxxxxxxxx
pppppxxxxxxyyyyyyyyyy(21 位=5+6+10 位)110110qqqqxxxxxx 110111yyyyyyyyyy(qqqq = ppppp − 1)

为了启用这种编码方案,BMP 有一个未使用的代码点范围为 0xD800–0xDFFF 的空隙。因此,领先代理、尾随代理和 BMP 代码点的范围是不相交的,使得在面对错误时解码更加健壮。以下函数将代码点编码为 UTF-16(稍后我们将看到一个使用它的示例):

function toUTF16(codePoint) {var TEN_BITS = parseInt('1111111111', 2);function u(codeUnit) {return '\\u'+codeUnit.toString(16).toUpperCase();}if (codePoint <= 0xFFFF) {return u(codePoint);}codePoint -= 0x10000;// Shift right to get to most significant 10 bitsvar leadingSurrogate = 0xD800 | (codePoint >> 10);// Mask to get least significant 10 bitsvar trailingSurrogate = 0xDC00 | (codePoint & TEN_BITS);return u(leadingSurrogate) + u(trailingSurrogate);
}

UCS-2,一种已弃用的格式,使用 16 位代码单元来表示(仅!)BMP 的代码点。当 Unicode 代码点的范围扩展到 16 位之外时,UTF-16 取代了 UCS-2。

UTF-8具有 8 位代码单元。它在传统 ASCII 编码和 Unicode 之间架起了一座桥梁。ASCII 只有 128 个字符,其编号与前 128 个 Unicode 代码点相同。UTF-8 是向后兼容的,因为所有 ASCII 代码都是有效的代码单元。换句话说,在范围 0–127 的单个代码单元中编码了相同范围内的单个代码点。这些代码单元的最高位为零。另一方面,如果最高位为 1,则会跟随更多的单元,以为更高的代码点提供额外的位。这导致了以下编码方案:

  • 0000–007F:0xxxxxxx(7 位,存储在 1 字节中)

  • 0080–07FF:110xxxxx,10xxxxxx(5+6 位=11 位,存储在 2 字节中)

  • 0800–FFFF:1110xxxx,10xxxxxx,10xxxxxx(4+6+6 位=16 位,存储在 3 字节中)

  • 10000–1FFFFF:11110xxx,10xxxxxx,10xxxxxx,10xxxxxx(3+6+6+6 位=21 位,存储在 4 字节中)。最高代码点是 10FFFF,因此 UTF-8 有一些额外的空间。

如果最高位不为 0,则零之前的 1 的数量表示序列中有多少个代码单元。初始单元之后的所有单元都具有位前缀 10。因此,初始代码单元和后续代码单元的范围是不相交的,这有助于从编码错误中恢复。

UTF-8 已成为最流行的 Unicode 格式。最初,它之所以受欢迎,是因为它与 ASCII 的向后兼容性。后来,它因其在操作系统、编程环境和应用程序中的广泛和一致的支持而受到青睐。

JavaScript 源代码和 Unicode

JavaScript 处理 Unicode 源代码有两种方式:内部(在解析期间)和外部(在加载文件时)。

内部源代码

在内部,JavaScript 源代码被视为一系列 UTF-16 代码单元。根据第 6 节的 EMCAScript 规范:

ECMAScript 源文本以 Unicode 字符编码的形式表示,版本为 3.0 或更高。[…] ECMAScript 源文本被假定为本规范的目的是一系列 16 位代码单元。[…] 如果实际源文本以除 16 位代码单元以外的形式编码,必须处理为首先转换为 UTF-16。

在标识符、字符串文字和正则表达式文字中,任何代码单元也可以通过 Unicode 转义序列\uHHHH来表示,其中HHHH是四个十六进制数字。例如:

> var f\u006F\u006F = 'abc';
> foo
'abc'> var λ = 123;
> \u03BB
123

这意味着您可以在源代码中使用 Unicode 字符的文字和变量名,而不会离开 ASCII 范围。

在字符串文字中,还有一种额外的转义可用:用两位十六进制数字表示的十六进制转义序列,表示范围在 0x00-0xFF 的代码单元。例如:

> '\xF6' === 'ö'
true
> '\xF6' === '\u00F6'
true

外部源代码

虽然内部使用 UTF-16,但 JavaScript 源代码通常不以该格式存储。当 Web 浏览器通过<script>标签加载源文件时,它会确定编码如下:

  • 如果文件以 BOM 开头,则编码是 UTF 变体,取决于使用的 BOM。

  • 否则,如果文件是通过 HTTP(S)加载的,那么Content-Type头可以通过charset参数指定编码。例如:

    Content-Type: application/javascript; charset=utf-8
    

提示

JavaScript 文件的正确媒体类型(以前称为MIME 类型)是application/javascript。但是,较旧的浏览器(例如 Internet Explorer 8 及更早版本)最可靠地使用text/javascript。不幸的是,<script>标签的type属性的默认值是text/javascript。至少对于 JavaScript,您可以省略该属性;包含它没有好处。

  • 否则,如果<script>标签具有charset属性,则将使用该编码。即使属性type包含有效的媒体类型,该类型也不得具有参数charset(就像前述的Content-Type头)。这确保了charsettype的值不会冲突。

  • 否则,使用包含<script>标签的文档的编码。例如,这是 HTML5 文档的开头,其中<meta>标签声明文档编码为 UTF-8:

    <!doctype html>
    <html>
    <head><meta charset="UTF-8">
    ...
    

强烈建议您始终指定编码。如果不指定,将使用特定于区域设置的默认编码。换句话说,在不同国家,人们将以不同方式看待文件。只有最低的 7 位在各个区域设置中相对稳定。

我的建议可以总结如下:

  • 对于您自己的应用程序,您可以使用 Unicode。但必须将应用程序的 HTML 页面的编码指定为 UTF-8。

  • 对于库,最安全的做法是发布 ASCII(7 位)代码。

一些缩小工具可以将具有超出 7 位的 Unicode 代码点的源代码转换为“7 位干净”的源代码。它们通过用 Unicode 转义替换非 ASCII 字符来实现。例如,以下调用UglifyJS将文件test.js翻译为:

uglifyjs -b beautify=false,ascii-only=true test.js

文件test.js如下所示:

var σ = 'Köln';

UglifyJS 的输出如下:

var \u03c3="K\xf6ln";

考虑以下负面示例。有一段时间,库 D3.js 以 UTF-8 发布。这导致了一个错误,因为当它从编码不是 UTF-8 的页面加载时,代码包含了诸如以下语句:

var π = Math.PI, ε = 1e-6;

标识符π和ε没有被正确解码,也没有被识别为有效的变量名。此外,一些超出 7 位的代码点的字符串文字也没有被正确解码。作为一种解决方法,您可以通过向<script>标签添加适当的charset属性来加载代码:

<script charset="utf-8" src="d3.js"></script>

JavaScript 字符串和 Unicode

JavaScript 字符串是一系列 UTF-16 代码单元。根据 ECMAScript 规范,第 8.4 节:

当一个字符串包含实际文本数据时,每个元素被认为是单个 UTF-16 代码单元。

转义序列

如前所述,您可以在字符串文字中使用 Unicode 转义序列和十六进制转义序列。例如,您可以通过将o与重音符(代码点 0x0308)组合来产生字符ö:

> console.log('o\u0308')
ö

这适用于 JavaScript 命令行,例如 Web 浏览器控制台和 Node.js REPL。您还可以将这种类型的字符串插入到 Web 页面的 DOM 中。

通过转义引用星际飞机字符

网络上有许多不错的 Unicode 符号表。看看 Tim Whitlock 的“Emoji Unicode Tables”,并对现代 Unicode 字体中有多少符号感到惊讶。表中的符号都不是图像;它们都是字体字形。假设您想通过 JavaScript 显示一个星际飞机中的 Unicode 字符(显然,这样做存在风险:并非所有字体都支持所有这些字符)。例如,考虑一头奶牛,代码点为 0x1F404:!

您可以复制字符并直接粘贴到您的 Unicode 编码 JavaScript 源代码中:

JavaScript 引擎将解码源代码(通常为 UTF-8)并创建一个具有两个 UTF-16 代码单元的字符串。或者,您可以自己计算两个代码单元并使用 Unicode 转义序列。有一些网络应用程序可以执行这种计算,例如:

  • UTF 转换器

  • Mathias Bynens 的“JavaScript 转义”

先前定义的函数toUTF16也执行了它:

> toUTF16(0x1F404)
'\\uD83D\\uDC04'

UTF-16 代理对(0xD83D,0xDC04)确实编码了奶牛:

计数字符

如果字符串包含代理对(两个编码单元编码一个代码点),那么length属性不再计算图形元素。它计算编码单元:

这可以通过库来修复,例如 Mathias Bynens 的Punycode.js,它与 Node.js 捆绑在一起:

> var puny = require('punycode');
> puny.ucs2.decode(str).length
1

Unicode 规范化

如果您想在字符串中搜索或比较它们,那么您需要进行规范化,例如通过库unorm(由 Bjarke Walling)。

JavaScript 正则表达式和 Unicode

JavaScript 正则表达式中的 Unicode 支持(请参阅第十九章)非常有限。例如,没有办法匹配“大写字母”等 Unicode 类别。

行终止符影响匹配。行终止符是下表中指定的四个字符之一:

代码单元名称字符转义序列
\u000A换行符\n
\u000D回车\r
\u2028行分隔符
\u2029段落分隔符

以下正则表达式构造基于 Unicode:

  • \s \S(空白,非空白)具有基于 Unicode 的定义:

    > /^\s$/.test('\uFEFF')
    true
    
  • .(点)匹配所有代码单元(不是代码点!)除了行终止符。请参阅下一节,了解如何匹配任何代码点。

  • 多行模式/m:在多行模式下,断言^匹配输入的开头和行终止符之后。断言$匹配行终止符之前和输入的结尾。在非多行模式下,它们只在输入的开头或结尾匹配。

其他重要的字符类是基于 ASCII 而不是 Unicode 定义的:

  • \d \D(数字,非数字):数字等同于[0-9]

  • \w \W(单词字符,非单词字符):单词字符等同于[A-Za-z0-9_]

  • \b \B(在单词边界,单词内):单词是由单词字符([A-Za-z0-9_])组成的序列。例如,在字符串'über'中,字符类转义\b将字符b视为单词的开始:

    > /\bb/.test('über')
    true
    

匹配任何代码单元和任何代码点

要匹配任何代码单元,您可以使用[\s\S];请参见原子:通用。

要匹配任何代码点,您需要使用:¹⁸

([\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])

前面的模式工作原理如下:

([BMP code point]|[leading surrogate][trailing surrogate])

由于所有这些范围都是不相交的,该模式将正确匹配 UTF-16 字符串中的代码点。

一些库可帮助处理 JavaScript 中的 Unicode:

  • Regenerate有助于生成像前面那样的范围,以匹配任何代码单元。它旨在用作构建工具的一部分,但也可以动态工作,用于尝试各种功能。

  • XRegExp是一个正则表达式库,它有一个官方附加组件,可以通过以下三种构造之一匹配 Unicode 类别、脚本、块和属性:

    \p{...} \p{^...} \P{...}
    

例如,\p{Letter}匹配各种字母表中的字母,而\p{^Letter}\P{Letter}都匹配所有其他代码点。第三十章包含了对 XRegExp 的简要概述。

  • ECMAScript 国际化 API(请参见ECMAScript 国际化 API)提供了对 Unicode 的排序和搜索等功能。

推荐阅读和章节来源

有关 Unicode 的更多信息,请参见以下内容:

  • 维基百科上有几篇关于Unicode及其术语的好文章。

  • Unicode.org,Unicode 联盟的官方网站,以及其FAQ也是很好的资源。

  • Joel Spolsky 的介绍性文章“每个软件开发人员绝对必须了解的有关 Unicode 和字符集的绝对最低限度(没有借口!)”很有帮助。

有关 JavaScript 中的 Unicode 支持的信息,请参见:

  • Mathias Bynens 的文章“JavaScript 的内部字符编码:UCS-2 还是 UTF-16?”

  • 《JavaScript,正则表达式和 Unicode》由 Steven Levithan

致谢

以下人员为本章做出了贡献:Mathias Bynens(@mathias),Anne van Kesteren(@annevk)和 Calvin Metcalf(@CWMma)。


¹⁸ 严格来说,任何Unicode 标量值。

第二十五章:ECMAScript 5 中的新功能

原文:25. New in ECMAScript 5

译者:飞龙

协议:CC BY-NC-SA 4.0

本章列出了仅在 ECMAScript 5 中可用的功能。如果您必须使用旧版 JavaScript 引擎,您应该避免使用这些功能,或者通过库启用其中一些功能(稍后将进行描述)。请注意,通常情况下,本书假定您正在使用完全支持 ECMAScript 5 的现代引擎。

ECMAScript 5 规范包含了对其范围的以下描述:

ECMAScript 的第五版(作为 ECMA-262 第 5 版发布)

  • 对已成为浏览器实现中常见的语言规范的实际解释进行了编码

  • 增加了对自第三版出版以来出现的新功能的支持。这些功能包括

    • 访问器属性,

    • 反射创建和检查对象,

    • 程序控制属性属性,

    • 附加数组操作函数,

    • 对 JSON 对象编码格式的支持,以及 x

    • 提供增强的错误检查和程序安全性的严格模式。

新功能

ECMAScript 5 中包含的新功能如下:

严格模式(参见严格模式)

将以下行放在文件或函数的开头可以打开所谓的严格模式,使 JavaScript 成为一个更干净的语言,禁止一些功能,执行更多检查,并抛出更多异常:

'use strict';

访问器(参见访问器(Getter 和 Setter))

Getter 和 setter 允许您通过方法实现属性的获取和设置。例如,以下对象obj包含属性foo的 getter:

> var obj = { get foo() { return 'abc' } };
> obj.foo
'abc'

语法更改

ECMAScript 5 包括以下语法更改:

保留字作为属性键

您可以在点运算符之后使用保留字(例如newfunction)并且在对象文字中作为非引用的属性键:

> var obj = { new: 'abc' };
> obj.new
'abc'

合法的尾随逗号

对象文字和数组文字中的尾随逗号是合法的。

多行字符串文字

如果通过反斜杠转义行尾,字符串文字可以跨多行。

标准库中的新功能

ECMAScript 5 为 JavaScript 的标准库带来了几个新增功能。本节按类别列出了它们。

元编程

获取和设置原型(参见获取和设置原型):

  • Object.create()

  • Object.getPrototypeOf()

通过属性描述符管理属性属性(参见属性描述符):

  • Object.defineProperty()

  • Object.defineProperties()

  • Object.create()

  • Object.getOwnPropertyDescriptor()

列出属性(参见迭代和属性检测):

  • Object.keys()

  • Object.getOwnPropertyNames()

保护对象(参见保护对象):

  • Object.preventExtensions()

  • Object.isExtensible()

  • Object.seal()

  • Object.isSealed()

  • Object.freeze()

  • Object.isFrozen()

新的Function方法(参见Function.prototype.bind(thisValue, arg1?, …, argN?)):

  • Function.prototype.bind()

新方法

字符串(参见第十二章):

  • 新方法String.prototype.trim()

  • 通过方括号操作符[...]访问字符

新的Array方法(参见[Array Prototype Methods](ch18.html#array_prototype_methods “Array Prototype Methods”):

  • Array.isArray()

  • Array.prototype.every()

  • Array.prototype.filter()

  • Array.prototype.forEach()

  • Array.prototype.indexOf()

  • Array.prototype.lastIndexOf()

  • Array.prototype.map()

  • Array.prototype.reduce()

  • Array.prototype.some()

新的Date方法(参见Date Prototype Methods):

  • Date.now()

  • Date.prototype.toISOString()

JSON

对 JSON 的支持(参见第二十二章):

  • JSON.parse()(参见JSON.parse(text, reviver?))

  • JSON.stringify()(参见JSON.stringify(value, replacer?, space?))

  • 一些内置对象具有特殊的toJSON()方法:

  • Boolean.prototype.toJSON()

  • Number.prototype.toJSON()

  • String.prototype.toJSON()

  • Date.prototype.toJSON()

与旧版浏览器一起工作的提示

如果您需要与旧版浏览器一起工作,以下资源将非常有用:

  • Juriy Zaytsev(“kangax”)的兼容性表显示了各种浏览器的各个版本支持 ECMAScript 5 的程度。

  • es5-shim 将 ECMAScript 5 的大部分(但不是全部)功能带到只支持 ECMAScript 3 的浏览器中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/615483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Verilog 和 System Verilog 的区别

当谈到VLSI设计和数字电路建模时&#xff0c;verilog和system verilog是两种常用的硬件描述语言。这些 HDL 在 VLSI 设计中用于描述电子电路的行为和结构。它们都广泛应用于半导体行业来设计和实现集成电路&#xff08;IC&#xff09;。 它们是设计和模拟复杂数字系统的强大工具…

解决:ModuleNotFoundError: No module named ‘dbutils’

解决&#xff1a;ModuleNotFoundError: No module named ‘dbutils’ 文章目录 解决&#xff1a;ModuleNotFoundError: No module named dbutils背景报错问题报错翻译报错位置代码报错原因解决方法方法一&#xff0c;直接安装方法二&#xff0c;手动下载安装方法三&#xff0c;…

盈利之道:下单前的必问之问

投资者在过去的交易经历中&#xff0c;通常都会面临所谓的“交易低谷”。交易低谷是指在交易过程中难以实现盈利或可能导致进一步亏损的阶段。这种面临损失或没有盈利的时期可能发生在任何人身上&#xff0c;无论是由于市场变化、投资者策略调整还是其他原因。为了应对这种情况…

Hibernate实战之操作MySQL数据库(2024-1-8)

Hibernate实战之操作MySQL数据库 2024.1.8 前提环境&#xff08;JavaMySQLNavicatVS Code&#xff09;1、Hibernate简介1.1 了解HQL 2、MySQL数据库建表2.1 编写SQL脚本2.2 MySQL执行脚本 3、Java操作MySQL实例&#xff08;Hibernate&#xff09;3.1 准备依赖的第三方jar包3.2 …

与听力学相关的职业都有哪些?怎么选择?

随着年龄的增长&#xff0c;每个人都可能面临听觉障碍的困惑。听力学领域专注于患者的耳朵问题&#xff0c;包括听力损失和平衡障碍。听力学职业是为患者提供听觉健康管理服务的职业&#xff0c;专注于他们耳朵的听力和平衡甚至言语相关需求。为患者进行听功能检查、测试、诊疗…

代码随想录算法训练营Day17|110.平衡二叉树、257. 二叉树的所有路径、 404.左叶子之和

文章目录 一、110.平衡二叉树1.递归法 二、257. 二叉树的所有路径1. 递归法 三、 404.左叶子之和1.迭代法 一、110.平衡二叉树 题目描述&#xff1a; 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a;一个二…

C++ Primer 6.2参数传递 知识点+练习题

C Primer 6.2参数传递 知识点练习题 指针形参使用引用拷贝Const 形参实参尽量使用常量引用数组形参数组引用形参传递多维数组向main函数传参数含有可变形参的函数练习题待更新 指针形参 void reset(int *p) {*p0;//p指向的整型对象变为0p0;//只是对形参改变p&#xff0c;使其为…

【Git】查看凭据管理器的账号信息,并删除账号,解决首次认证登录失败后无法重新登录的问题

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是是《代码管理工具》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的…

性能测试分析案例-定位内核线程CPU利用率太高

环境准备 预先安装 docker、perf、hping3、curl 等工具&#xff0c;如 apt install docker.io linux-tools-common hping3 操作和分析 Linux 在启动过程中&#xff0c;有三个特殊的进程&#xff0c;也就是 PID 号最小的三个进程。 0 号进程为 idle 进程&#xff0c;这也是系…

Windows 项目从0到1的部署

目录 一. 安装jdk 1.1 安装jdk 1.2 配置jdk的环境配置jdk 1.3 配置成功 二. 配置tomcat 2.1 启动tomcat 2.2 防火墙设置 三. 安装MySQL 3.1 安装步骤 3.2 内部连接 3.3 外部连接 四. 部署项目 4.1 项目部署 4.2 修改mysql的用户密码 一. 安装jdk 这里给大家准备好了jdk和…

2024.1.8 Day04_SparkCore_homeWork

目录 1. 简述Spark持久化中缓存和checkpoint检查点的区别 2 . 如何使用缓存和检查点? 3 . 代码题 浏览器Nginx案例 先进行数据清洗,做后续需求用 1、需求一&#xff1a;点击最多的前10个网站域名 2、需求二&#xff1a;用户最喜欢点击的页面排序TOP10 3、需求三&#x…

一卡通水控电控开发踩过的坑

最近在做一个项目&#xff0c;是对接一卡通设备的。我一开始只拿到设备和3个文档开局。不知道从哪下手。一步一步踩坑过来。踩了很多没有必要的坑&#xff0c;写出来给有用的人吧。 读卡器怎么用&#xff1f; 有个读卡器&#xff0c;一开始什么软件也不提供。我都不知道是干嘛…

Jupyter Notebook

2017年左右在大学里都听说过Jupyter Notebook&#xff0c;并且也安装用了一段时间&#xff0c;后来不知道什么原因没有用了。估计是那时候写代码的时候多一些&#xff0c;因为它可以直接写代码并运行结果&#xff0c;现在不怎么写代码了。 介绍 后缀名为.ipynb的json格式文件…

《YOLO算法:基础+进阶+改进》报错解决 专栏答疑

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。《YOLO算法&#xff1a;基础进阶改进》专栏上线后&#xff0c;部分同学在学习过程中提出了一些问题&#xff0c;笔者相信这些问题其他同学也有可能遇到。为了让大家可以更好地学习本专栏内容&#xff0c;笔者特意推出了该篇…

SpringBoot集成Camunda

一&#xff1a;SpringBoot集成 1.1&#xff1a;pom.xml 因camunda集成SpringBoot对SpringBoot的版本和JDK的版本都有一定的要求&#xff0c;所以这里贴个完整的依赖。可以去官网找每个SpringBoot的版本对应的camunda版本。 <?xml version"1.0" encoding"…

前端入门教程:学完即可单独完成前端项目

目录 目录 1.HTML: 1.1概念 1.2结构 1.3常见的标签使用分类&#xff1a; 2.CSS: 2.1概念 2.2样式实践&#xff1a; 以下的举例都来自于博客&#xff1a; 2.3css选择器&#xff1a; 什么是css选择器&#xff1a; 举例如下&#xff1a; 2.4Demo 3.JavaScript&#…

算法34:贴纸拼词(力扣691题)

题目&#xff1a; 我们有 n 种不同的贴纸。每个贴纸上都有一个小写的英文单词。 您想要拼写出给定的字符串 target &#xff0c;方法是从收集的贴纸中切割单个字母并重新排列它们。如果你愿意&#xff0c;你可以多次使用每个贴纸&#xff0c;每个贴纸的数量是无限的。 返回你…

vivado IP Revision Control

2020.2 只需要git 管理 prj.xpr 和 prj.srcs/ https://china.xilinx.com/video/hardware/ip-revision-control.html https://www.xilinx.com/video/hardware/vivado-design-suite-revision-control.html

每日一题:LeetCode-LCR 007. 三数之和

每日一题系列&#xff08;day 18&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

linux高级篇基础理论十一(GlusterFS)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…