ES6-Class
# # ES6-Class
ES6 的class可以看作只是一个语法糖,注意以下几个可能会犯错误的点。
# # 1. 实例属性和原型方法
实例属性
除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层(等于号赋值)
。
类中的方法是定义在原型链上(Animal.prototyp)
,包括getter/setter函数。
详细可看Babel Class解析为ES5的代码 (opens new window) (opens new window)
class Animal {
// 实例属性,定义在类实例对象上(a.speak1)
name = 'MyAnimal'
speak1 = () => {
return this
}
// 原型链方法,定义在原型上(Animal.prototype.speak)
speak() {
return this;
}
// get也是定义在原型上(Animal.prototype.[get getName])
get getName() {
return this.name
}
}
const a = new Animal()
console.log(a) // { name: 'MyAnimal', speak1: f , __proto__: {constructor, speak, ...} }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# # 2. this 指向
实例属性this在定义时就已确定指向当前实例(箭头函数)。
类的方法(包括get/set函数)this默认指向当前实例,但一旦遇到解构时(上下文环境变化),this的值可能变化。
class Animal {
// 实例属性。this在书写代码时,就已经确定为当前实例对象(箭头函数)
speak1 = () => {
console.log(this, 'speak1') // 在代码
return this
}
// 原型链方法。this依赖于运行环境,默认是当前实例对象
speak() {
console.log(this, 'speak')
return this;
}
}
let a = new Animal()
a.speak() // a
a.speak1() // a
let { speak, speak1 } = a
speak() // undefined。重要:解构后原型链上的方法,this为undefined
speak1() // a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# # 3. 继承时的原型链
类继承时,属性是直接继承,而原型链上的方法是一层一层的继承。
class B extends Animal {
b1 = () => {
console.log(this)
}
b() {
console.log(this)
}
}
// B(属性)->B.prototype -> A.prototype
console.log(new B()) // { speak1, b1, __proto__(B): {b, __proto__(A): {speak} } }
class C extends B {
c1 = () => {
console.log(this)
}
c() {
console.log(this)
}
}
// C(属性) -> C.prototype ->B.prototype -> A.prototype
console.log(new C()) // { speak1, b1, c1, __proto__(C): {c, __proto__(B): {b, __proto__(A):{speak} } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# # 4. ES5和ES6继承的不同
ES5的继承
,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。
ES6的继承
则不同,在单重继承时,基本同ES5一致;当多重继承时,子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。详细看以下babel es6转es5 _possibleConstructorReturn应用。
es6:
class Person {
static body = 'bofy';
constructor(age) {
this.name = 123
this.age = age
}
getName() {
return this.name
}
}
class Doctor extends Person {
constructor(age) {
super(age)
this.skill = 'shoushu'
}
}
// 多重继承
class Superman extends Doctor {
}
var d = new Doctor(35)
d.name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
babel 转译为 es5:
"use strict";
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj &&
typeof Symbol === "function" &&
obj.constructor === Symbol &&
obj !== Symbol.prototype
? "symbol"
: typeof obj;
};
}
return _typeof(obj);
}
function _possibleConstructorReturn(self, call) {
// call有值,则返回call
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return self
}
function _getPrototypeOf(o) {
// setPrototypeOf是ES6提案
_getPrototypeOf = Object.setPrototypeOf
? Object.getPrototypeOf
: function _getPrototypeOf(o) {
// getPrototypeOf在ES5就有,只是ES6中有一些改动
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
// 原型链继承
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
// 实现继承
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { value: subClass, writable: true, configurable: true }
});
// 设置subClass.__proto__ = superClass,为的是getPrototypOf时能拿到superClass这个构造函数。
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf =
Object.setPrototypeOf ||
function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _instanceof(left, right) {
if (
right != null &&
typeof Symbol !== "undefined" &&
right[Symbol.hasInstance]
) {
return right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
// 只允许new方式创建class
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
var Person =
/*#__PURE__*/
(function() {
function Person(age) {
// 检查必须使用new关键字创建类实例
_classCallCheck(this, Person);
this.name = 123;
this.age = age;
}
// class中的方法,都是在Person.prototype
// class中的静态属性,都是在Person上
_createClass(Person, [
{
key: "getName",
value: function getName() {
return this.name;
}
}
]);
return Person;
})();
_defineProperty(Person, "body", "bofy");
var Doctor =
/*#__PURE__*/
(function(_Person) {
// Doctor继承自Person
// Doctor.prototype.__proto__ === Person.prototype(因为Doctor.prototype = Object.create(Person.prototype))
// Doctor.__proto__ === Person(因为Object.setPrototypeOf(Doctor, Person))
_inherits(Doctor, _Person);
function Doctor() {
var _this;
_classCallCheck(this, Doctor);
/**
* 子类必须在constructor方法中调用super方法,否则新建实例时会报错。
* 等同于
* _this = Person.call(this, age) ?Person.call(this, age) : this
* 在单重继承时,Person.call()执行后返回空;多重继承时, Person.call()有值返回
* **/
_this = _possibleConstructorReturn(
this,
_getPrototypeOf(Doctor).call(this, age)
);
_this.skill = "shoushu";
// 返回this。在多重继承中,this是父类的this(即:子类实例的构建,基于父类实例。)
return _this;
}
return Doctor;
})(Person);
var Superman =
/*#__PURE__*/
function (_Doctor) {
_inherits(Superman, _Doctor);
function Superman() {
_classCallCheck(this, Superman);
/**
* class有多重继承特征,此时子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。
**/
return _possibleConstructorReturn(this, _getPrototypeOf(Superman).apply(this, arguments));
}
return Superman;
}(Doctor);
var d = new Doctor(35);
d.name;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
编辑 (opens new window)