@@ -88,9 +88,9 @@ let b = new B();
88
88
b .constructor === B .prototype .constructor // true
89
89
```
90
90
91
- 上面代码中,b是B类的实例,它的constructor方法就是B类原型的constructor方法 。
91
+ 上面代码中,` b ` 是B类的实例,它的 ` constructor ` 方法就是B类原型的 ` constructor ` 方法 。
92
92
93
- 由于类的方法(除constructor以外)都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面 。` Object.assign ` 方法可以很方便地一次向类添加多个方法。
93
+ 由于类的方法(除 ` constructor ` 以外)都定义在 ` prototype ` 对象上面,所以类的新方法可以添加在 ` prototype ` 对象上面 。` Object.assign ` 方法可以很方便地一次向类添加多个方法。
94
94
95
95
``` javascript
96
96
class Point {
@@ -618,7 +618,19 @@ p1.printName() // "Ha"
618
618
619
619
## 原生构造函数的继承
620
620
621
- 原生构造函数是指语言内置的构造函数,通常用来生成数据结构,比如` Array() ` 。以前,这些原生构造函数是无法继承的,即不能自己定义一个Array的子类。
621
+ 原生构造函数是指语言内置的构造函数,通常用来生成数据结构。ECMAScript的原生构造函数大致有下面这些。
622
+
623
+ - Boolean()
624
+ - Number()
625
+ - String()
626
+ - Array()
627
+ - Date()
628
+ - Function()
629
+ - RegExp()
630
+ - Error()
631
+ - Object()
632
+
633
+ 以前,这些原生构造函数是无法继承的,比如,不能自己定义一个Array的子类。
622
634
623
635
``` javascript
624
636
function MyArray () {
@@ -635,7 +647,7 @@ MyArray.prototype = Object.create(Array.prototype, {
635
647
});
636
648
```
637
649
638
- 上面代码定义了一个继承Array的MyArray类 。但是,这个类的行为与Array完全不一致。
650
+ 上面代码定义了一个继承Array的`MyArray`类 。但是,这个类的行为与Array完全不一致。
639
651
640
652
```javascript
641
653
var colors = new MyArray();
@@ -646,9 +658,9 @@ colors.length = 0;
646
658
colors[0] // "red"
647
659
```
648
660
649
- 之所以会发生这种情况,是因为原生构造函数无法外部获取 ,通过`Array.apply()`或者分配给原型对象都不行。ES5是先新建子类的实例对象this ,再将父类的属性添加到子类上,由于父类的属性无法获取 ,导致无法继承原生的构造函数。
661
+ 之所以会发生这种情况,是因为子类无法获得原生构造函数的内部属性 ,通过`Array.apply()`或者分配给原型对象都不行。ES5是先新建子类的实例对象`this` ,再将父类的属性添加到子类上,由于父类的内部属性无法获取 ,导致无法继承原生的构造函数。比如,Array构造函数有一个内部属性`[[DefineOwnProperty]]`,用来定义新属性时,更新`length`属性,这个内部属性无法在子类获取,导致子类的`length`属性行为不正常 。
650
662
651
- ES6允许继承原生构造函数定义子类,因为ES6是先新建父类的实例对象this,然后再用子类的构造函数修饰this ,使得父类的所有行为都可以继承。下面是一个继承Array的例子。
663
+ ES6允许继承原生构造函数定义子类,因为ES6是先新建父类的实例对象`this`,然后再用子类的构造函数修饰`this` ,使得父类的所有行为都可以继承。下面是一个继承Array的例子。
652
664
653
665
```javascript
654
666
class MyArray extends Array {
@@ -667,7 +679,7 @@ arr[0] // undefined
667
679
668
680
上面代码定义了一个MyArray类,继承了Array构造函数,因此就可以从MyArray生成数组的实例。这意味着,ES6可以自定义原生数据结构(比如Array、String等)的子类,这是ES5无法做到的。
669
681
670
- 上面这个例子也说明,extends关键字不仅可以用来继承类 ,还可以用来继承原生的构造函数。因此可以在原生数据结构的基础上,定义自己的数据结构。下面就是定义了一个带版本功能的数组。
682
+ 上面这个例子也说明,` extends ` 关键字不仅可以用来继承类 ,还可以用来继承原生的构造函数。因此可以在原生数据结构的基础上,定义自己的数据结构。下面就是定义了一个带版本功能的数组。
671
683
672
684
` ` ` javascript
673
685
class VersionedArray extends Array {
@@ -679,14 +691,29 @@ class VersionedArray extends Array {
679
691
this .history .push (this .slice ());
680
692
}
681
693
revert () {
682
- this .splice (0 , this .length , this .history [this .history .length - 1 ]);
694
+ this .splice (0 , this .length , ... this .history [this .history .length - 1 ]);
683
695
}
684
696
}
697
+
698
+ var x = new VersionedArray ();
699
+
700
+ x .push (1 );
701
+ x .push (2 );
702
+ x // [1, 2]
703
+ x .history // [[]]
704
+
705
+ x .commit ();
706
+ x .history // [[], [1, 2]]
707
+ x .push (3 );
708
+ x // [1, 2, 3]
709
+
710
+ x .revert ();
711
+ x // [1, 2]
685
712
` ` `
686
713
687
- 上面代码中,VersionedArray结构会通过commit方法,将自己的上一个版本存入history属性,然后通过revert方法 ,可以撤销当前版本,回到上一个版本。除此之外,VersionedArray依然是一个数组 ,所有原生的数组方法都可以在它上面调用。
714
+ 上面代码中,` VersionedArray ` 结构会通过 ` commit ` 方法,将自己的当前状态存入 ` history ` 属性,然后通过 ` revert ` 方法 ,可以撤销当前版本,回到上一个版本。除此之外,` VersionedArray ` 依然是一个数组 ,所有原生的数组方法都可以在它上面调用。
688
715
689
- 下面是一个自定义Error子类的例子 。
716
+ 下面是一个自定义 ` Error ` 子类的例子 。
690
717
691
718
` ` ` javascript
692
719
class ExtendableError extends Error {
@@ -714,7 +741,7 @@ myerror.stack
714
741
// ...
715
742
` ` `
716
743
717
- ## class的取值函数 (getter)和存值函数(setter)
744
+ ## Class的取值函数 (getter)和存值函数(setter)
718
745
719
746
与ES5一样,在Class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
720
747
0 commit comments