前言
在 ECMAScript 6 中新引入了 class
关键字,具有定义类的能力。其实际上还是使用了原型和构造函数的概念。
类的类型时 function
,类不进行声明提升,类受块级作用域的限制,类可以作为参数传递
class Person {
constructor(name) {
this._myName = name;
}
sayName() {
console.log('我的名字是: ' + this._myName);
}
set myName(value) {
this._myName = value;
}
get myName() {
return this._myName;
}
static sayHi() {
console.log('Hi');
}
}
var a = new Person('knight');
a;
class Son extends Person {
constructor(name, age) {
super(name);
this.age = age;
}
}
使用类有以下好处:
- 不再引用杂乱的
.prototype
了 Button
声明时直接“继承”了Widget
,不再需要通过Object.create()
来替换.ptototype
对象,也不需要设置.__proto__
或者Object.setPrototypeOf()
- 可以通过
super()
来实现相对多态,这样任何方法都可以引用原型链上层的同名方法。 class
字面语法不能声明属性,只能声明方法。会排除掉许多不好的情况- 可以通过
extends
很自然地扩展对象子类型,甚至时内置的对象子类型
类的声明
我们可以通过类声明和类表达式来声明一个类:
// 类声明
class Person1 {}
// 类表达式
var Person2 = class {}
类构造函数
如果我们声明类的时候不定义类构造函数,则相当于将构造函数定义为空函数,如果我们的类有父类,则自动调用父类的构造函数。
使用 new
操作符实例化 Person
的操作等于使用 new
调用其构造函数
使用 new
调用类的构造函数会执行如下操作:
- 在内存中创建一个新对象
- 这个新对象内部的
[[Prototype]]
指针(存储其原型对象,对开发者不可见,在大多数浏览器中可以通过__proto__
去访问)被赋值为构造函数的prototype
属性 - 构造函数内部的
this
被赋值为这个新对象(即this
指向新对象 - 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数发挥非空对象,则返回该对象;否则返回刚创建的新对象
在实例化之后,类构造函数会以普通函数作为实例的一个属性
方法
我们可以添加方法和静态类方法,也可以添加获取和设置访问器。
我们添加的方法将作为原型方法定义在原型对象中,供所有实例调用
静态方法将定义在 .contructor
构造函数中,可通过类名调用
设置的访问器将作为实例的属性,添加到实例对象中
class Person {
constructor(name) {
this._myName = name;
}
sayName() {
console.log('我的名字是: ' + this._myName);
}
set myName(value) {
this._myName = value;
}
get myName() {
return this._myName;
}
static sayHi() {
console.log('Hi');
}
}
var a = new Person('knight');
a;
类的继承
继承类可通过 extends
关键字,不但可以继承类,还可以继承构造函数
function First(name) {
this.name = name;
}
First.name = 'first';
class Second extends First {
constructor(name, age) {
super(name);
this.age = age
}
}
Second.name = 'second';
class Third extends Second {}
Third.name = 'third';
var a = new First('knight');
var b = new Second('knight', 19);
var c = new Third('knight', 18);
super
派生类的方法可以通过 super
关键字引用他们的原型。
使用 super
有一下几个注意点:
- 这个关键字只能在派生类中使用,而且仅限于类构造函数、实例方法和静态方法内部
- 不能单独引用
super
关键字 - 调用
super()
会调用父类构造方法,并将返回的实例赋值给this
super()
的行为如同调用构造函数,如果需要给父类构造函数传参,需要手动传入- 如果没有定义类构造函数,在实例化派生类时会调用
super()
,而且会传入所有传给派生类的参数 - 在类构造函数中,不能在调用
super()
之前引用this
- 如果在派生类中显示定义了构造函数,则要么必须在其中国调用
super()
,要么必须在其中返回一个对象
class Person {
constructor(name) {
this._myName = name;
}
sayName() {
console.log('我的名字是: ' + this._myName);
}
set myName(value) {
this._myName = value;
}
get myName() {
return this._myName;
}
static sayHi() {
console.log('Hi');
}
}
class Son extends Person {
constructor(name, age) {
super(name);
this.age = age;
}
sayInfo() {
super.sayName();
console.log('我的年龄是: ' + this.age);
}
static sayHellow() {
super.sayHi();
}
}
var a = new Son('knight', 18);