【ES6】class学习

前言

之前写过一篇剪短的class文章,这次在学习TS的时候,发现对于class的掌握还不是很熟练,于是参考阮一峰老师的《ES6入门》深入学习


写法

如何定义一个类呢?

class Human{
  constructor(name, gender, age){
    this.name = name
    this.gender = gender
    this.age = age
  }
  eat(){
    console.log(`${this.name}饿了,吃饭中···`)
  }
}
  • constructor 方法
    类似于强类型语言的构造方法
    constructor方法是类的默认方法,通过new操作符生成对象实例时,会自动调用该方法。一个类必须有constructor方法,如果在定义类时没有显示定义,会被默认添加一个空的constructor方法。
    constructor方法默认返回实例对象(即this),但也可以指定返回另一个对象。
class Fn{
  constructor (){
    return Object.create(null),
  }
}

new Fn() instanceof Fn  //false

类与ES5的构造函数主要区别是:
类必须使用new操作符来调用,而ES5的构造函数不用new也会执行。


类的实例

ES5一样,实例的属性除非显示定义在本身上,否则都是定义在原型上。
类的所有实例都共享一个原型对象

class Fn{
  constructor(x, y){
    this.x = x
    this.y = y
    this.fn = () => {console.log(`这是实例上的方法`)}
  }
  fn(){
    console.log(`这是原型上的方法`)
   }
}

const a = new Fn(1, 2)
a.fn()  //这是实例上的方法
a.__proto__.fn()  //这是原型上的方法

const b = new Fn('a', 'b')
a.__proto__ === b.__proto__  //true

注意点

  • 严格模式
    类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块中,就只有严格模式可用。

  • 不存在变量提升
    类不存在变量提升,这与ES5完全不同

new Fn()  //error
class Fn(){}
  • name属性
    本质上,ES6的类只是ES5的构造函数的一层包装,所以函数的许多特性都被class继承,包括name属性。

  • this的指向
    类的方法内部如果含有this,它默认指向类的实例。但如果单独使用该方法,很可能报错,因为当你调用一个函数时,this的指向由调用者决定。


静态方法

类相当于实例的原型,所有定义在类中的方法,都会被实例继承,如果在一个方法前加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就是“静态方法”,并且静态方法还可以和非静态方法重名。
如果静态方法内部包含this关键字,这个this指向的是类,不是实例。

class Fn{
  constructor(){}
  static classMethod(){
   this.bar()   
  }
  static bar(){
    console.log('我是类方法')
  }
  bar(){
    console.log('我是原型上的方法')
  }
}

Fn.classMethod()  //我是类方法

父类的静态方法可以被子类继承


实例属性的新写法

实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。

class Human{
  name
  age
  gender
  constructor(){}
}

const a = new Human()
a.name  //undefined
a.age  //undefined

静态属性

静态属性是类本身的属性,不是定义在实例对象上的属性,目前最新版的Chrome浏览器已经支持类的静态属性了。

class Fn{
  static prop = 'Hello World'
  constructor(){}
}

Fn.prop  //Hello World

new.target属性

new是从构造函数生成实例对象的命令,ES6为new命令引入了一个new.target属性,一般用于构造函数中,返回new操作符作用对象的构造函数,如果构造函数不是通过nwe调用的,那么new.target会返回 undefined,所以这个属性可以确定构造函数是否通过new调用。

function fn(value){
  if(new.target !== undefined){
    this.value= value
  }else{
    throw new Error('必须使用new操作符生成实例对象')
  }
}

const a = new fn(666)  //正确
const b = fn(666)  //error

在Class内部调用new.target,返回当前Class,子类继承父类是,new.target返回子类。


Class的继承

Class可以通过extends关键字实现继承,相对于ES5通过修改原型链实现继承更加清晰和方便。

class Human{
  constructor(name, age, gender){
    this.name = name
    this.age = age
    this.gender = gender
  }
  eat(){
    console.log('吃饭中···')
  }
}

class Man extends Human{
  constructor(name, age, stature){
    super(name, age)
    this.stature = stature
    this.gender = 'man'
  }
}

const zink = new Man('zink', 21, 174)
zink.eat()  //吃饭中···

ES5的继承是先创造子类对象this,然后将父类的方法绑定到this上(Parent.apply(this))。ES6的机制跟ES5完全不同,先将父类实例对象的属性和方法添加到this上,再用子类的构造哈数修改this

注意点:

  • 子类必须在构造方法里调用super方法,且必须在调用super方法之后在修改this的属性,否则会报错。

super关键字

super这个关键字,既可以当做函数使用,也可以当做对象使用。但是用法不同。

  • 作为函数调用
    super作为函数调用时,只能在子类的constructor方法里调用,代表父类的构造函数。super虽然代表了父类的构造函数,但是返回的是子类的实例,也就是说super内部的this指向子类的实例,所以super()相当于是父类.prototype.constructor.call(this)

  • 作为对象调用
    普通方法中,super表示父类的原型对象,此时只能访问父类原型实例上的属性,并且通过super访问的方法内部的this指向子类实例。
    静态方法中super表示指向父类,此时只能访问父类的静态属性和方法(即用static关键字标注的属性和方法),此时方法内部的this指向子类而不是子类实例

你可能感兴趣的:(【ES6】class学习)