mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 18:32:22 +00:00
fix #81
This commit is contained in:
parent
965a2dbb49
commit
5a5f9d8d49
@ -53,7 +53,7 @@ typeof Point // "function"
|
|||||||
|
|
||||||
上面代码表明,类的数据类型就是函数。
|
上面代码表明,类的数据类型就是函数。
|
||||||
|
|
||||||
构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,除了constructor方法以外,类的方法都定义在类的prototype属性上面。
|
构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
class Point {
|
class Point {
|
||||||
@ -73,11 +73,23 @@ class Point {
|
|||||||
// 等同于
|
// 等同于
|
||||||
|
|
||||||
Point.prototype = {
|
Point.prototype = {
|
||||||
|
constructor(){},
|
||||||
toString(){},
|
toString(){},
|
||||||
toValue(){}
|
toValue(){}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
在类的实例上面调用方法,其实就是调用原型上的方法。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class B {}
|
||||||
|
let b = new B();
|
||||||
|
|
||||||
|
b.constructor === B.prototype.constructor // true
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,b是B类的实例,它的constructor方法就是B类原型的constructor方法。
|
||||||
|
|
||||||
由于类的方法(除constructor以外)都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。`Object.assign`方法可以很方便地一次向类添加多个方法。
|
由于类的方法(除constructor以外)都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。`Object.assign`方法可以很方便地一次向类添加多个方法。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -419,7 +431,7 @@ cp instanceof Point // true
|
|||||||
|
|
||||||
### 类的prototype属性和\_\_proto\_\_属性
|
### 类的prototype属性和\_\_proto\_\_属性
|
||||||
|
|
||||||
在ES5中,每一个对象都有`__proto__`属性,指向对应的构造函数的prototype属性。Class作为构造函数的语法糖,同时有prototype属性和`__proto__`属性,因此同时存在两条继承链。
|
大多数浏览器的ES5实现之中,每一个对象都有`__proto__`属性,指向对应的构造函数的prototype属性。Class作为构造函数的语法糖,同时有prototype属性和`__proto__`属性,因此同时存在两条继承链。
|
||||||
|
|
||||||
(1)子类的`__proto__`属性,表示构造函数的继承,总是指向父类。
|
(1)子类的`__proto__`属性,表示构造函数的继承,总是指向父类。
|
||||||
|
|
||||||
|
@ -150,9 +150,9 @@ for (var f of flat(arr)){
|
|||||||
|
|
||||||
### 与Iterator的关系
|
### 与Iterator的关系
|
||||||
|
|
||||||
上一章说过,任意一个对象的Symbol.iterator属性,等于该对象的遍历器函数,调用该函数会返回该对象的一个遍历器。
|
上一章说过,任意一个对象的`Symbol.iterator`方法,等于该对象的遍历器函数,调用该函数会返回该对象的一个遍历器。
|
||||||
|
|
||||||
遍历器本身也是一个对象,它的Symbol.iterator属性执行后,返回自身。
|
遍历器本身也是一个对象,它的`Symbol.iterator`方法执行后,返回自身。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function* gen(){
|
function* gen(){
|
||||||
@ -331,7 +331,7 @@ try {
|
|||||||
|
|
||||||
上面代码之所以只捕获了a,是因为函数体外的catch语句块,捕获了抛出的a错误以后,就不会再继续执行try语句块了。
|
上面代码之所以只捕获了a,是因为函数体外的catch语句块,捕获了抛出的a错误以后,就不会再继续执行try语句块了。
|
||||||
|
|
||||||
如果遍历器函数内部没有部署try...catch代码块,那么throw方法抛出的错误,将被外部try...catch代码块捕获。
|
如果Generator函数内部没有部署try...catch代码块,那么throw方法抛出的错误,将被外部try...catch代码块捕获。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var g = function* () {
|
var g = function* () {
|
||||||
@ -355,7 +355,7 @@ try {
|
|||||||
|
|
||||||
上面代码中,遍历器函数g内部,没有部署try...catch代码块,所以抛出的错误直接被外部catch代码块捕获。
|
上面代码中,遍历器函数g内部,没有部署try...catch代码块,所以抛出的错误直接被外部catch代码块捕获。
|
||||||
|
|
||||||
如果遍历器函数内部部署了try...catch代码块,那么遍历器的throw方法抛出的错误,不影响下一次遍历,否则遍历直接终止。
|
如果Generator函数内部部署了try...catch代码块,那么遍历器的throw方法抛出的错误,不影响下一次遍历,否则遍历直接终止。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var gen = function* gen(){
|
var gen = function* gen(){
|
||||||
@ -374,7 +374,7 @@ try {
|
|||||||
// hello
|
// hello
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码只输出hello就结束了,因为第二次调用next方法时,遍历器状态已经变成终止了。但是,如果使用throw方法抛出错误,不会影响遍历器状态。
|
上面代码只输出hello就结束了,因为第二次调用next方法时,遍历器状态已经变成终止了。但是,如果使用throw命令抛出错误,不会影响遍历器状态。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var gen = function* gen(){
|
var gen = function* gen(){
|
||||||
@ -529,7 +529,7 @@ for(let value of delegatingIterator) {
|
|||||||
// "Ok, bye."
|
// "Ok, bye."
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,delegatingIterator是代理者,delegatedIterator是被代理者。由于`yield* delegatedIterator`语句得到的值,是一个遍历器,所以要用星号表示。运行结果就是使用一个遍历器,遍历了多个Genertor函数,有递归的效果。
|
上面代码中,delegatingIterator是代理者,delegatedIterator是被代理者。由于`yield* delegatedIterator`语句得到的值,是一个遍历器,所以要用星号表示。运行结果就是使用一个遍历器,遍历了多个Generator函数,有递归的效果。
|
||||||
|
|
||||||
yield*语句等同于在Generator函数内部,部署一个for...of循环。
|
yield*语句等同于在Generator函数内部,部署一个for...of循环。
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ interface IterationResult {
|
|||||||
|
|
||||||
Iterator接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环(详见下文)。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找Iterator接口。
|
Iterator接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环(详见下文)。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找Iterator接口。
|
||||||
|
|
||||||
ES6规定,默认的Iterator接口部署在数据结构的`Symbol.iterator`属性,或者一个数据结构只要具有`Symbol.iterator`属性,就可以认为是“可遍历的”(iterable)。也就是说,调用`Symbol.iterator`方法,就会得到当前数据结构的默认遍历器。`Symbol.iterator`本身是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为Symbol的特殊值,所以要放在方括号内(请参考Symbol一节)。
|
ES6规定,默认的Iterator接口部署在数据结构的`Symbol.iterator`属性,或者说,一个数据结构只要具有`Symbol.iterator`属性,就可以认为是“可遍历的”(iterable)。调用`Symbol.iterator`方法,就会得到当前数据结构的默认遍历器。`Symbol.iterator`本身是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为Symbol的特殊值,所以要放在方括号内(请参考Symbol一章)。
|
||||||
|
|
||||||
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。
|
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ let obj = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
对于类似数组的对象(存在数值键名和length属性),部署Iterator接口,有一个简便方法,就是`Symbol.iterator`方法直接引用数值的Iterator接口。
|
对于类似数组的对象(存在数值键名和length属性),部署Iterator接口,有一个简便方法,就是`Symbol.iterator`方法直接引用数组的Iterator接口。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
|
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
|
||||||
@ -265,10 +265,9 @@ while (!$result.done) {
|
|||||||
|
|
||||||
**(1)解构赋值**
|
**(1)解构赋值**
|
||||||
|
|
||||||
对数组和Set结构进行解构赋值时,会默认调用iterator接口。
|
对数组和Set结构进行解构赋值时,会默认调用`Symbol.iterator`方法。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|
||||||
let set = new Set().add('a').add('b').add('c');
|
let set = new Set().add('a').add('b').add('c');
|
||||||
|
|
||||||
let [x,y] = set;
|
let [x,y] = set;
|
||||||
@ -276,7 +275,6 @@ let [x,y] = set;
|
|||||||
|
|
||||||
let [first, ...rest] = set;
|
let [first, ...rest] = set;
|
||||||
// first='a'; rest=['b','c'];
|
// first='a'; rest=['b','c'];
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**(2)扩展运算符**
|
**(2)扩展运算符**
|
||||||
@ -337,7 +335,6 @@ iterator.next() // { value: undefined, done: true }
|
|||||||
《数组的扩展》一章中提到,ES6对数组提供entries()、keys()和values()三个方法,就是返回三个遍历器。
|
《数组的扩展》一章中提到,ES6对数组提供entries()、keys()和values()三个方法,就是返回三个遍历器。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|
||||||
var arr = [1, 5, 7];
|
var arr = [1, 5, 7];
|
||||||
var arrEntries = arr.entries();
|
var arrEntries = arr.entries();
|
||||||
|
|
||||||
@ -346,7 +343,6 @@ arrEntries.toString()
|
|||||||
|
|
||||||
arrEntries === arrEntries[Symbol.iterator]()
|
arrEntries === arrEntries[Symbol.iterator]()
|
||||||
// true
|
// true
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,entries方法返回的是一个遍历器(iterator),本质上就是调用了`Symbol.iterator`方法。
|
上面代码中,entries方法返回的是一个遍历器(iterator),本质上就是调用了`Symbol.iterator`方法。
|
||||||
@ -354,7 +350,6 @@ arrEntries === arrEntries[Symbol.iterator]()
|
|||||||
字符串是一个类似数组的对象,也原生具有Iterator接口。
|
字符串是一个类似数组的对象,也原生具有Iterator接口。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|
||||||
var someString = "hi";
|
var someString = "hi";
|
||||||
typeof someString[Symbol.iterator]
|
typeof someString[Symbol.iterator]
|
||||||
// "function"
|
// "function"
|
||||||
@ -364,7 +359,6 @@ var iterator = someString[Symbol.iterator]();
|
|||||||
iterator.next() // { value: "h", done: false }
|
iterator.next() // { value: "h", done: false }
|
||||||
iterator.next() // { value: "i", done: false }
|
iterator.next() // { value: "i", done: false }
|
||||||
iterator.next() // { value: undefined, done: true }
|
iterator.next() // { value: undefined, done: true }
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,调用`Symbol.iterator`方法返回一个遍历器,在这个遍历器上可以调用next方法,实现对于字符串的遍历。
|
上面代码中,调用`Symbol.iterator`方法返回一个遍历器,在这个遍历器上可以调用next方法,实现对于字符串的遍历。
|
||||||
|
@ -67,7 +67,7 @@ export function multiply (x, y) {
|
|||||||
|
|
||||||
import {firstName, lastName, year} from './profile';
|
import {firstName, lastName, year} from './profile';
|
||||||
|
|
||||||
function sfirsetHeader(element) {
|
function setName(element) {
|
||||||
element.textContent = firstName + ' ' + lastName;
|
element.textContent = firstName + ' ' + lastName;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -124,7 +124,7 @@ export function circumference(radius) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
然后,main.js文件输入circlek.js模块。
|
然后,main.js文件输入circle.js模块。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// main.js
|
// main.js
|
||||||
@ -296,7 +296,7 @@ export { area as circleArea } from 'circle';
|
|||||||
|
|
||||||
module math from "circleplus";
|
module math from "circleplus";
|
||||||
import exp from "circleplus";
|
import exp from "circleplus";
|
||||||
console.log(exp(math.pi));
|
console.log(exp(math.PI));
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中的"import exp"表示,将circleplus模块的默认方法加载为exp方法。
|
上面代码中的"import exp"表示,将circleplus模块的默认方法加载为exp方法。
|
||||||
|
@ -260,7 +260,7 @@ someAsyncThing().then(function() {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,someAsyncThing函数产生的Promise对象会报错,但是由于没有调用catch方法,这个错误不会被捕获,也不会传递到外层代码,导致运行后没有任何输出。
|
上面代码中,someAsyncThing函数产生的Promise对象会报错,但是由于没有指定catch方法,这个错误不会被捕获,也不会传递到外层代码,导致运行后没有任何输出。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var promise = new Promise(function(resolve, reject) {
|
var promise = new Promise(function(resolve, reject) {
|
||||||
@ -272,7 +272,7 @@ promise.then(function(value) { console.log(value) });
|
|||||||
// Uncaught Error: test
|
// Uncaught Error: test
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,Promise指定在下一轮“事件循环”再抛出错误,结果由于没有指定catch语句,就冒泡到最外层,成了未捕获的错误。
|
上面代码中,Promise指定在下一轮“事件循环”再抛出错误,结果由于没有指定使用try...catch语句,就冒泡到最外层,成了未捕获的错误。因为此时,Promise的函数体已经运行结束了,所以这个错误是在Promise函数体外抛出的。
|
||||||
|
|
||||||
Node.js有一个unhandledRejection事件,专门监听未捕获的reject错误。
|
Node.js有一个unhandledRejection事件,专门监听未捕获的reject错误。
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ ES6原生提供Proxy构造函数,用来生成Proxy实例。
|
|||||||
var proxy = new Proxy(target, handler)
|
var proxy = new Proxy(target, handler)
|
||||||
```
|
```
|
||||||
|
|
||||||
Proxy对象的所用用法,都是上面这种形式,不同的只是handler参数的写法。其中,`new Proxy()`表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
|
Proxy对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,`new Proxy()`表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
|
||||||
|
|
||||||
下面是另一个拦截读取属性行为的例子。
|
下面是另一个拦截读取属性行为的例子。
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ let obj = Object.create(proxy);
|
|||||||
obj.time // 35
|
obj.time // 35
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,proxy对象是obj对象的原型,obj对象本身并没有time属性,所有根据原型链,会在proxy对象上读取该属性,导致被拦截。
|
上面代码中,proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截。
|
||||||
|
|
||||||
同一个拦截器函数,可以设置拦截多个操作。
|
同一个拦截器函数,可以设置拦截多个操作。
|
||||||
|
|
||||||
@ -368,6 +368,7 @@ Reflect对象的方法清单如下。
|
|||||||
- Reflect.defineProperty(target,name,desc)
|
- Reflect.defineProperty(target,name,desc)
|
||||||
- Reflect.getOwnPropertyNames(target)
|
- Reflect.getOwnPropertyNames(target)
|
||||||
- Reflect.getPrototypeOf(target)
|
- Reflect.getPrototypeOf(target)
|
||||||
|
- Reflect.setPrototypeOf(target, prototype)
|
||||||
- Reflect.deleteProperty(target,name)
|
- Reflect.deleteProperty(target,name)
|
||||||
- Reflect.enumerate(target)
|
- Reflect.enumerate(target)
|
||||||
- Reflect.freeze(target)
|
- Reflect.freeze(target)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
|
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
|
||||||
|
|
||||||
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第八种数据类型,前七种是:数值、字符串、布尔值、数组、对象、函数、undefined。
|
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
|
||||||
|
|
||||||
Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
|
Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user