原型链篇:一文读懂class类

380 阅读3分钟

Function实现一个Class


function person(name, age) {
  this.name = name
  this.age = age
}
person.prototype.getName = function() {
   console.log('person name is:'+ this.name)
}
const person = new person('xiaoye', 18)
person.getName() // person name is:xiaoye
person.age // 18

// 等价于

class Person {
  // Person构造函数
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  // Person原型上的方法
  getName() {
    console.log('person name is:'+ this.name)
  }
}

const person = new Person('xiaoye', 18)
person.getName() // person name is:xiaoye
person.age // 18

image.png

通过上述结果,可以得出class就是一个关键字,是function的一个语法糖

class中的constructor就是其构造函数,里面的方法就是挂载在原型上的方法,在class中定义的方法不需要通过function去定义,否则会报错。

Class的静态属性

class Person {
  static height=180
  // Person构造函数
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  // Person构造函数的方法
  static setAge(age) {
   this.age = age
  }
  static getAge() {
    console.log('person age is:'+ this.age)
  }
  getInfo() {
    this.getAge()
  }
  getStaticAge() {
    Person.getAge()
  }
   getHeight(){
    console.log('person height is:' + Person.height)
  }
}

const person = new Person('xiaoye', 18)
person.getAge() // Uncaught TypeError: person.getAge is not a function
person.getInfo() // Uncaught TypeError: this.getAge is not a function
person.getStaticAge() // person age is:undefined
Person.getAge() // person age is:undefined
Person.setAge(12)
person.getStaticAge() // person age is:12
Person.getAge() // person age is:12

image.png

由于静态方法是挂载在构造函数的对象上在原型上是找不到的,所以只能被通过Person直接对其进行调用。

Class的私有属性

class Person {
  // Person构造函数
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  getAge() {
    console.log(this.age)
  }
  #getName() {
    console.log(this.name)
  }
  getInfo() {
    this.getAge()
    this.#getName()
  }
}

const person = new Person('xiaoye', 18)
this.getAge() // 18
this.getName() // VM706:1 Uncaught TypeError: person.getName is not a function
this.getInfo() // 18 xiaoye

通过#可以将类中的方法和属性设置为私有属性,只能在类中被进行调用

extends继承

class Parent {
  constructor() {
    this.parentName = 'xiaoye';
    this.parentAge = 20;
  }
  parentFunc() {
    console.log(this.parentName);
  }
}

// class Child extends Parent 等价于 Child.prototype = new Parent() 
class Child extends Parent {
  constructor() {
    super();  // 等价于 Parent.call(Child.prototype)
    this.childName = 'xiaoming';
    this.childAge = 18;
  }
  childFunc() {
    console.log(this.childName)
  }
}

let child = new Child();

image.png

class的继承的设计思想在我看来就是利用了组合继承的优点来实现的,可以达到:

1.继承父类原型方法

2.可以向父类传递参数

3.子类继承父类的引用类型属性不会被共享的优点。

super关键字

class Parent {
  constructor() {
    this.parentName = 'xiaoye';
    this.parentAge = 20;
  }
  parentFunc() {
    console.log(this.parentName);
  }
}

// class Child extends Parent 等价于 Child.prototype = new Parent() 
class Child extends Parent {
  constructor() {
    this.childName = 'xiaoming';
    this.childAge = 18;
  }
  childFunc() {
    console.log(this.childName)
  }
}

let child = new Child(); // Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。所以在上述继承中导致新建实例时报错。

super的两种场景

构造函数

class Parent {
  constructor() {
  }
}


class Child extends Parent {
  constructor() {
    super();  
    this.age = 18
  }
  childFunc() {
    super(); //Uncaught SyntaxError: 'super' keyword unexpected here
  }
  getAge() {
    console.log(this.age)
  }
}

let child = new Child();


super在constructor中会被当做构造函数来看待,等价于A.prototype.constructor.call(this),并且在super()不能在其他方法中进行使用,否则会报错

引用对象

class Parent {
  constructor(name) {
    this.name = name
  }
  getName() {
    console.log(this.name)
  }
}


class Child extends Parent {
  constructor(name) {
    super(name);  
    this.age = 18
  }
  getParentName() {
    super.getName(); 
  }
}

let child = new Child('xiaoye');

child.getParentName() // xiaoye

super在方法中会被当做引用类型来看待,不能在consructor中使用,否则会报错

总而言之,class的出现就是为了使程序可以更加面向对象开发,相比es5的继承写法更加直观,实际的底层实现还是围绕着原型链进行开展的,如果读不懂可以阅读一下本人前面几篇关于原型链的文章巩固下原型链相关的基础再进行阅读。