一、类
前言:在Es6中类可以把它看作是一个语法糖,它的大部分功能Es5都能实现。
不同的是Es5除了可以用new调用还可以用其他的方式调用,而类只能用new调用。
// Es5
function Fn() {
this.a = 'a'
}
let fn = new Fn()
// Es6
class Fn {
constructor() {
this.a = a
}
}
let fn = new Fn()
在Es6类中必须有一个constructor方法,如果没有显示定义那么会在类的内部自动加入一个空的constructor方法。
class Fn {
constructor() {
this.a = a // this指向的是实例
}
}
let fn = new Fn()
在类中属性是定义在实例中,方法定义在类的原型上[Prototype],并且它们是不可枚举的。类方法内部的this指向的是实例。
class Fn {
constructor() {
this.a = 'a' // this指向的是实例
}
show() {
console.log(this); // this指向的是实例
}
}
let fn = new Fn()
console.log(Fn.prototype.hasOwnProperty('show')); true
console.log(fn.hasOwnProperty('a')); true
类中属性的另一种定义方式
class Fn {
a = 'a' // 定义在类的顶部
constructor() {
}
show() {
console.log(this.a); // this指向的是实例
}
}
let fn = new Fn()
fn.show()
如果在类中的方法前面加上static关键字,那么这个 方法就是一个静态方法。静态方法是定义在类的constructor上,静态方法内部的this则指向类。
注意:静态方法只能通过类调用,静态方法及属性可以被子类继承。
// Es6
class Fn {
static a = 'a' // 静态属性,定义在类的constructor上。constructor.a = 'a'
constructor() {
}
// 静态方法,定义在类的constructor上。constructor.show = function(){}
static show() {
console.log(this.a); // this指向的是Fn
}
}
Fn.show()
let fn = new Fn()
在类中如果一个方法加上#关键字,那么这个方法就是私有方法。私有方法定义在类的[PrivateMethods]上。私有方法内部的this则指向实例。
注意:私有方法只能在类的内部使用,不能被子类继承。
class Fn {
#a = 'a' // 私有属性,定义在类的实例上
constructor() {
}
// 私有方法定义在类的[PrivateMethods]
#show() {
console.log(this.#a); // this指向的是实例
}
show() {
this.#show()
}
}
let fn = new Fn()
fn.show()
console.log(fn);
与Es5一致,类的内部可以使用getter,setter。用于类某个属性存值、取值拦截。
class Fn {
constructor() {
this.a = 10
}
get _a() {
return this.a
}
set _a(val) {
if (val > 10) {
this.a = 0
}
}
}
let fn = new Fn()
fn._a = 11
console.log(fn._a);
二、类的继承
在Es6中类的继承是由extends关键字来完成。
class Fn {
constructor() {
this.a = 10
}
}
class Point extends Fn {
constructor() { }
}
子类继承父类需要在子类的constructor方法中通过super调用父类的constructor方法来完成子类的this塑造。得到与父类同样的实例在此基础上进行加工将子类的属性和方法追加上。
注意:如果没有调用super子类得不到自己this
class Fn {
constructor() {
this.a = 10
}
}
class Point extends Fn {
constructor() {
this.a = 20
}
}
let point = new Point()
class Fn {
constructor() {
this.a = 10
}
}
class Point extends Fn {
constructor() {
super() // 调用父类的constructor方法,得到子类的this
this.a = 20
}
}
let point = new Point()
console.log(point.a); // 20
为什么要在子类的constructor方法中调用super。是因为Es6与Es5的继承机制不同。
- Es5是先创建一个子类的实例,再将父类的属性和方法加到子类上。即:实列在前,继承在后
- Es6是先将父类的属性和方法加到一个对象上,将这个对象作为子类的实例。即:继承在前,实例在后
注意:super只能在子类的constructor方法中调用!super可以当作对象引用,还可以当作函数调用。 由于super指向的是父类的原型,而不是父类的实例,所以父类实例中的方法和属性不能得到。
在子类方法中调用父类的普通方法时,父类方法内部的this指向的是子类的实例
class Fn {
constructor() {
this.a = 10
}
show() {
console.log(this.a); // this指向的是子类的实例
}
}
class Point extends Fn {
constructor() {
super()
this.a = 20
}
show() {
super.show() // 调用父类的方法
}
}
let point = new Point()
point.show() // 20
通过子类调用父类的静态方法,父类静态方法内部的this指向的是子类
class Fn {
static a = 10
constructor() {
}
static show() {
console.log(this.a); // this指向的是子类
}
}
class Point extends Fn {
static a = 20
constructor() {
super()
}
show() {
Point.show() // 调用父类的静态方法
}
}
let point = new Point()
point.show() // 20