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