1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

edit string & promise

This commit is contained in:
ruanyf 2015-10-02 12:10:21 +08:00
parent 8ef1e5a876
commit 6c3396809c
5 changed files with 220 additions and 66 deletions

View File

@ -1,20 +1,22 @@
# 二进制数组
二进制数组ArrayBuffer对象、TypedArray对象、DataView对象是JavaScript操作二进制数据的一个接口。这些对象早就存在属于独立的规格ES6将它们纳入了ECMAScript规格并且增加了新的方法。
二进制数组ArrayBuffer对象、TypedArray视图和DataView视图是JavaScript操作二进制数据的一个接口。这些对象早就存在属于独立的规格ES6将它们纳入了ECMAScript规格并且增加了新的方法。
这个接口的原始设计目的与WebGL项目有关。所谓WebGL就是指浏览器与显卡之间的通信接口为了满足JavaScript与显卡之间大量的、实时的数据交换它们之间的数据通信必须是二进制的而不能是传统的文本格式。文本格式传递一个32位整数两端的JavaScript脚本与显卡都要进行格式转化将非常耗时。这时要是存在一种机制可以像C语言那样直接操作字节将4个字节的32位整数以二进制形式原封不动地送入显卡脚本的性能就会大幅提升。
二进制数组就是在这种背景下诞生的。它很像C语言的数组允许开发者以数组下标的形式直接操作内存大大增强了JavaScript处理二进制数据的能力使得开发者有可能通过JavaScript与操作系统的原生接口进行二进制通信。
二进制数组由三对象组成。
二进制数组由三对象组成。
**1ArrayBuffer对象**:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。
**2) TypedArray对象**用来生成内存的视图通过9个构造函数可以生成9种数据格式的视图比如Uint8Array无符号8位整数数组视图, Int16Array16位整数数组视图, Float32Array32位浮点数数组视图等等。
**2) TypedArray视图**共包括9种类型的视图比如Uint8Array无符号8位整数数组视图, Int16Array16位整数数组视图, Float32Array32位浮点数数组视图等等。
**3DataView对象**:用来生成内存的视图,可以自定义格式和字节序比如第一个字节是Uint8无符号8位整数、第二、三个字节是Int1616位整数、第四个字节开始是Float3232位浮点数等等。
**3DataView视图**:可以自定义复合格式的视图比如第一个字节是Uint8无符号8位整数、第二、三个字节是Int1616位整数、第四个字节开始是Float3232位浮点数等等,此外还可以自定义字节序
简单说ArrayBuffer对象代表原始的二进制数据TypedArray对象代表确定类型的二进制数据DataView对象代表不确定类型的二进制数据。它们支持的数据类型一共有9种DataView对象支持除Uint8C以外的其他8种
简单说ArrayBuffer对象代表原始的二进制数据TypedArray视图用来读写简单类型的二进制数据DataView视图用来读写复杂类型的二进制数据。
TypedArray视图支持的数据类型一共有9种DataView视图支持除Uint8C以外的其他8种
数据类型 | 字节长度 | 含义 | 对应的C语言类型
--------|--------|----|---------------
@ -134,13 +136,13 @@ var v = new Int32Array(buffer);
ArrayBuffer.isView(v) // true
```
## TypedArray对象
## TypedArray视图
### 概述
`ArrayBuffer`对象作为内存区域可以存放多种类型的数据。同一段内存不同数据有不同的解读方式这就叫做“视图”view`ArrayBuffer`有两种视图一种是TypedArray视图另一种是DataView视图,两者的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。
`ArrayBuffer`对象作为内存区域可以存放多种类型的数据。同一段内存不同数据有不同的解读方式这就叫做“视图”view`ArrayBuffer`有两种视图一种是TypedArray视图另一种是DataView视图前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。
目前TypedArray对象一共提供9种类型的视图,每一种视图都是一种构造函数。
目前TypedArray视图一共包括9种类型,每一种视图都是一种构造函数。
- **Int8Array**8位有符号整数长度1个字节。
- **Uint8Array**8位无符号整数长度1个字节。
@ -152,7 +154,7 @@ ArrayBuffer.isView(v) // true
- **Float32Array**32位浮点数长度4个字节。
- **Float64Array**64位浮点数长度8个字节。
这9个构造函数生成的对象统称为TypedArray对象。它们很像普通数组,都有`length`属性,都能用方括号运算符(`[]`)获取单个元素,所有数组的方法,在TypedArray数组上面都能使用。普通数组与TypedArray数组的差异主要在以下方面。
这9个构造函数生成的数组统称为TypedArray视图。它们很像普通数组,都有`length`属性,都能用方括号运算符(`[]`)获取单个元素,所有数组的方法,在它们上面都能使用。普通数组与TypedArray数组的差异主要在以下方面。
- `TypedArray`数组的所有成员,都是同一种类型。
- `TypedArray`数组的成员是连续的,不会有空位。

View File

@ -322,7 +322,7 @@ yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历
```javascript
let generator = function* () {
yield 1;
yield* [2,3,4]; //use an iterable, is looped, and added as yields
yield* [2,3,4];
yield 5;
};

View File

@ -22,7 +22,29 @@ import { stat, exists, readFile } from 'fs';
上面代码的实质是从`fs`模块加载3个方法其他方法不加载。这种加载称为“编译时加载”即ES6可以在编译时就完成模块编译效率要比CommonJS模块的加载方式高。
需要注意的是ES6的模块自动采用严格模式不管你有没有在模块头部加上`"use strict"`
## 严格模式
ES6的模块自动采用严格模式不管你有没有在模块头部加上`"use strict"`
严格模式主要有以下限制。
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用`with`语句
- 不能对只读属性赋值,否则报错
- 不能使用前缀0表示八进制数否则报错
- 不能删除不可删除的属性,否则报错
- 不能删除变量`delete prop`,会报错,只能删除属性`delete global[prop]`
- `eval`不会在它的外层作用域引入变量
- `eval``arguments`不能被重新赋值
- `arguments`不会自动反映函数参数的变化
- 不能使用`arguments.callee`
- 不能使用`arguments.caller`
- 禁止`this`指向全局对象
- 不能使用`fn.caller``fn.arguments`获取函数调用的堆栈
- 增加了保留字(比如`protected``static``interface`
上面这些限制,模块都必须遵守。
## export命令
@ -60,9 +82,9 @@ export function multiply (x, y) {
};
```
上面代码对外输出一个函数multiply。
上面代码对外输出一个函数`multiply`
通常情况下export输出的变量就是本来的名字但是可以使用as关键字重命名。
通常情况下,`export`输出的变量就是本来的名字,但是可以使用`as`关键字重命名。
```javascript
function v1() { ... }
@ -79,6 +101,24 @@ export {
最后,`export`命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,下面的`import`命令也是如此。
```javascript
function foo () {
export default 'bar' // SyntaxError
}
foo()
```
上面代码中,`export`语句放在函数之中,结果报错。
`export`语句输出的值是动态绑定,绑定其所在的模块。
```javascript
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
```
上面代码输出变量`foo`,值为`bar`500毫秒之后变成`baz`
## import命令
使用`export`命令定义了模块的对外接口以后其他JS文件就可以通过`import`命令加载这个模块(文件)。
@ -139,6 +179,14 @@ export v from "mod";
export {v} from "mod";
```
`import`语句会执行所加载的模块,因此可以有下面的写法。
```javascript
import 'lodash'
```
上面代码仅仅执行`lodash`模块,但是不输入任何值。
## 模块的整体加载
除了指定加载某个输出值,还可以使用整体加载,即用星号(`*`)指定一个对象,所有输出值都加载在这个对象上面。

View File

@ -134,9 +134,23 @@ var p2 = new Promise(function(resolve, reject){
})
```
上面代码中p1和p2都是Promise的实例但是p2的resolve方法将p1作为参数即一个异步操作的结果是返回另一个异步操作。
上面代码中,`p1``p2`都是Promise的实例但是`p2``resolve`方法将`p1`作为参数,即一个异步操作的结果是返回另一个异步操作。
注意这时p1的状态就会传递给p2也就是说p1的状态决定了p2的状态。如果p1的状态是Pending那么p2的回调函数就会等待p1的状态改变如果p1的状态已经是Resolved或者Rejected那么p2的回调函数将会立刻执行。
注意,这时`p1`的状态就会传递给`p2`,也就是说,`p1`的状态决定了`p2`的状态。如果`p1`的状态是`Pending`,那么`p2`的回调函数就会等待`p1`的状态改变;如果`p1`的状态已经是`Resolved`或者`Rejected`,那么`p2`的回调函数将会立刻执行。
```javascript
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
var p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2.then(result => console.log(result))
p2.catch(error => console.log(error))
// Error: fail
```
上面代码中,`p1`是一个Promise3秒之后变为`rejected``p2`的状态由`p1`决定1秒之后`p2`调用`resolve`方法,但是此时`p1`的状态还没有改变,因此`p2`的状态也不会变。又过了2秒`p1`变为`rejected``p2`也跟着变为`rejected`
## Promise.prototype.then()
@ -349,19 +363,19 @@ someAsyncThing().then(function() {
## Promise.all()
Promise.all方法用于将多个Promise实例包装成一个新的Promise实例。
`Promise.all`方法用于将多个Promise实例包装成一个新的Promise实例。
```javascript
var p = Promise.all([p1,p2,p3]);
```
上面代码中Promise.all方法接受一个数组作为参数p1、p2、p3都是Promise对象的实例。Promise.all方法的参数不一定是数组但是必须具有iterator接口且返回的每个成员都是Promise实例。
上面代码中,`Promise.all`方法接受一个数组作为参数,`p1``p2``p3`都是Promise对象的实例,如果不是,就会先调用下面讲到的`Promise.resolve`方法将参数转为Promise实例再进一步处理。(`Promise.all`方法的参数不一定是数组但是必须具有iterator接口且返回的每个成员都是Promise实例。
p的状态由p1、p2、p3决定分成两种情况。
`p`的状态由`p1``p2``p3`决定,分成两种情况。
1只有p1、p2、p3的状态都变成fulfilledp的状态才会变成fulfilled此时p1、p2、p3的返回值组成一个数组传递给p的回调函数。
1只有`p1``p2``p3`的状态都变成`fulfilled``p`的状态才会变成`fulfilled`,此时`p1``p2``p3`的返回值组成一个数组,传递给`p`的回调函数。
2只要p1、p2、p3之中有一个被rejectedp的状态就变成rejected此时第一个被reject的实例的返回值会传递给p的回调函数。
2只要`p1``p2``p3`之中有一个被`rejected``p`的状态就变成`rejected`,此时第一个被`reject`的实例的返回值,会传递给`p`的回调函数。
下面是一个具体的例子。
@ -379,15 +393,30 @@ Promise.all(promises).then(function(posts) {
```
## Promise.race()
Promise.race方法同样是将多个Promise实例包装成一个新的Promise实例。
`Promise.race`方法同样是将多个Promise实例包装成一个新的Promise实例。
```javascript
var p = Promise.race([p1,p2,p3]);
```
上面代码中只要p1、p2、p3之中有一个实例率先改变状态p的状态就跟着改变。那个率先改变的Promise实例的返回值就传递给p的回调函数。
上面代码中,只要`p1``p2``p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。那个率先改变的Promise实例的返回值就传递给`p`的回调函数。
如果Promise.all方法和Promise.race方法的参数不是Promise实例就会先调用下面讲到的Promise.resolve方法将参数转为Promise实例再进一步处理。
`Promise.race`方法的参数与`Promise.all`方法一样如果不是Promise实例就会先调用下面讲到的`Promise.resolve`方法将参数转为Promise实例再进一步处理。
下面是一个例子如果指定时间内没有获得结果就将Promise的状态变为`reject`,否则变为`resolve`
```javascript
var p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
```
上面代码中如果5秒之内`fetch`方法无法返回结果,变量`p`的状态就会变为`rejected`,从而触发`catch`方法指定的回调函数。
## Promise.resolve()
@ -397,7 +426,15 @@ var p = Promise.race([p1,p2,p3]);
var jsPromise = Promise.resolve($.ajax('/whatever.json'));
```
上面代码将jQuery生成deferred对象转为一个新的Promise对象。
上面代码将jQuery生成的`deferred`对象转为一个新的Promise对象。
`Promise.resolve`等价于下面的写法。
```javascript
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
```
如果Promise.resolve方法的参数不是具有then方法的对象又称thenable对象则返回一个新的Promise对象且它的状态为Resolved。
@ -428,17 +465,17 @@ p.then(function () {
## Promise.reject()
Promise.reject(reason)方法也会返回一个新的Promise实例该实例的状态为rejected。Promise.reject方法的参数reason会被传递给实例的回调函数。
`Promise.reject(reason)`方法也会返回一个新的Promise实例该实例的状态为`rejected``Promise.reject`方法的参数`reason`,会被传递给实例的回调函数。
```javascript
var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('foo'))
p.then(null, function (s){
console.log(s)
});
// 出错了
```
上面代码生成一个Promise对象的实例p状态为rejected回调函数会立即执行。

View File

@ -11,7 +11,7 @@ JavaScript允许采用`\uxxxx`形式表示一个字符其中“xxxx”表示
// "a"
```
但是,这种表示法只限于\u0000——\uFFFF之间的字符。超出这个范围的字符必须用两个双字节的形式表达。
但是,这种表示法只限于`\u0000`——`\uFFFF`之间的字符。超出这个范围的字符,必须用两个双字节的形式表达。
```javascript
"\uD842\uDFB7"
@ -21,7 +21,7 @@ JavaScript允许采用`\uxxxx`形式表示一个字符其中“xxxx”表示
// " 7"
```
上面代码表示,如果直接在“\u”后面跟上超过`0xFFFF`的数值(比如\u20BB7JavaScript会理解成“\u20BB+7”。由于\u20BB是一个不可打印字符所以只会显示一个空格后面跟着一个7。
上面代码表示,如果直接在“\u”后面跟上超过`0xFFFF`的数值(比如`\u20BB7`JavaScript会理解成“\u20BB+7”。由于`\u20BB`是一个不可打印字符所以只会显示一个空格后面跟着一个7。
ES6对这一点做出了改进只要将码点放入大括号就能正确解读该字符。
@ -41,7 +41,7 @@ hell\u{6F} // 123
上面代码中最后一个例子表明大括号表示法与四字节的UTF-16编码是等价的。
有了这种表示法之后JavaScript共有5种方法可以表示一个字符。
有了这种表示法之后JavaScript共有6种方法可以表示一个字符。
```javascript
'\z' === 'z' // true
@ -51,26 +51,6 @@ hell\u{6F} // 123
'\u{7A}' === 'z' // true
```
## String.fromCodePoint()
ES5提供String.fromCharCode方法用于从码点返回对应字符但是这个方法不能识别辅助平面的字符编号大于0xFFFF
```javascript
String.fromCharCode(0x20BB7)
// "ஷ"
```
上面代码中最后返回码点U+0BB7对应的字符而不是码点U+20BB7对应的字符。
ES6提供了String.fromCodePoint方法可以识别0xFFFF的字符弥补了String.fromCharCode方法的不足。在作用上正好与codePointAt方法相反。
```javascript
String.fromCodePoint(0x20BB7)
// "𠮷"
```
注意fromCodePoint方法定义在String对象上而codePointAt方法定义在字符串的实例对象上。
## codePointAt()
JavaScript内部字符以UTF-16的格式储存每个字符固定为2个字节。对于那些需要4个字节储存的字符Unicode码点大于0xFFFF的字符JavaScript会认为它们是两个字符。
@ -113,18 +93,70 @@ is32Bit("𠮷") // true
is32Bit("a") // false
```
## String.fromCodePoint()
ES5提供`String.fromCharCode`方法,用于从码点返回对应字符,但是这个方法不能识别辅助平面的字符(编号大于`0xFFFF`)。
```javascript
String.fromCharCode(0x20BB7)
// "ஷ"
```
上面代码中,`String.fromCharCode`不能识别大于`0xFFFF`的码点,所以`0x20BB7`就发生了溢出,最高位`2`被舍弃了,最后返回码点`U+0BB7`对应的字符,而不是码点`U+20BB7`对应的字符。
ES6提供了`String.fromCodePoint`方法,可以识别`0xFFFF`的字符,弥补了`String.fromCharCode`方法的不足。在作用上,正好与`codePointAt`方法相反。
```javascript
String.fromCodePoint(0x20BB7)
// "𠮷"
```
注意,`fromCodePoint`方法定义在String对象上`codePointAt`方法定义在字符串的实例对象上。
## 字符串的遍历器接口
ES6为字符串添加了遍历器接口详见《Iterator》一章使得字符串可以被`for...of`循环遍历。
```javascript
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
```
除了遍历字符串,这个遍历器最大的优点是可以识别大于`0xFFFF`的码点,传统的`for`循环无法识别这样的码点。
```javascript
var text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "𠮷"
```
上面代码中,字符串`text`只有一个字符,但是`for`循环会认为它包含两个字符(都不可打印),而`for...of`循环会正确识别出这一个字符。
## at()
ES5对字符串对象提供charAt方法返回字符串给定位置的字符。该方法不能识别码点大于0xFFFF的字符。
ES5对字符串对象提供`charAt`方法,返回字符串给定位置的字符。该方法不能识别码点大于`0xFFFF`的字符。
```javascript
'abc'.charAt(0) // "a"
'𠮷'.charAt(0) // "\uD842"
```
上面代码中charAt方法返回的是UTF-16编码的第一个字节实际上是无法显示的。
上面代码中,`charAt`方法返回的是UTF-16编码的第一个字节实际上是无法显示的。
ES7提供了字符串实例的at方法可以识别Unicode编号大于0xFFFF的字符返回正确的字符。Chrome浏览器已经支持该方法。
ES7提供了字符串实例的`at`方法可以识别Unicode编号大于`0xFFFF`的字符返回正确的字符。Chrome浏览器已经支持该方法。
```javascript
'abc'.at(0) // "a"
@ -133,7 +165,7 @@ ES7提供了字符串实例的at方法可以识别Unicode编号大于0xFFFF
## normalize()
为了表示语调和重音符号Unicode提供了两种方法。一种是直接提供带重音符号的字符比如Ǒ\u01D1。另一种是提供合成符号combining character即原字符与重音符号的合成两个字符合成一个字符比如O\u004F和ˇ\u030C合成Ǒ\u004F\u030C
为了表示语调和重音符号Unicode提供了两种方法。一种是直接提供带重音符号的字符比如Ǒ\u01D1。另一种是提供合成符号combining character即原字符与重音符号的合成两个字符合成一个字符比如`O`\u004F`ˇ`\u030C合成`Ǒ`\u004F\u030C
这两种表示方法在视觉和语义上都等价但是JavaScript不能识别。
@ -146,7 +178,7 @@ ES7提供了字符串实例的at方法可以识别Unicode编号大于0xFFFF
上面代码表示JavaScript将合成字符视为两个字符导致两种表示方法不相等。
ES6提供String.prototype.normalize()方法用来将字符的不同表示方法统一为同样的形式这称为Unicode正规化。
ES6提供`String.prototype.normalize()`方法用来将字符的不同表示方法统一为同样的形式这称为Unicode正规化。
```javascript
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
@ -178,32 +210,67 @@ normalize方法可以接受四个参数。
- **endsWith()**:返回布尔值,表示参数字符串是否在源字符串的尾部。
```javascript
var s = "Hello world!";
var s = 'Hello world!';
s.startsWith("Hello") // true
s.endsWith("!") // true
s.includes("o") // true
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
```
这三个方法都支持第二个参数,表示开始搜索的位置。
```javascript
var s = "Hello world!";
var s = 'Hello world!';
s.startsWith("world", 6) // true
s.endsWith("Hello", 5) // true
s.includes("Hello", 6) // false
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
```
上面代码表示使用第二个参数n时endsWith的行为与其他两个方法有所不同。它针对前n个字符而其他两个方法针对从第n个位置直到字符串结束。
## repeat()
repeat()返回一个新字符串表示将原字符串重复n次。
`repeat`方法返回一个新字符串表示将原字符串重复n次。
```javascript
"x".repeat(3) // "xxx"
"hello".repeat(2) // "hellohello"
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
```
参数如果是小数,会被取整。
```javascript
'na'.repeat(2.9) // "nana"
```
如果`repeat`的参数是负数或者`Infinity`,会报错。
```javascript
'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
```
但是如果参数是0到-1之间的小数则等同于0这是因为会先进行取整运算。0到-1之间的小数取整以后等于`-0``repeat`视同为0。
```javascript
'na'.repeat(-0.9) // ""
```
参数`NaN`等同于0。
```javascript
'na'.repeat(NaN) // ""
```
如果`repeat`的参数是字符串,则会先转换成数字。
```javascript
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"
```
## 模板字符串