class

42 阅读4分钟

简介

类(class)是es6中新增地基础性语法糖结构,提供了更加简洁、易读和易维护的语法。但他背后使用的仍热是原型和构造函数的概念,不可以被提升,受块级作用域影响。是一个函数

类的构成包含构造函数方法,实例方法,获取函数,设置函数和静态类方法

定义

  • 类声明
  • 类表达式
class Person { }
const Animal = class { }

构造函数constructor

constructor关键字用于在类定义块内部创建创建类的构造函数。在使用new操作符创建类的实例时会自动调用构造函数

使用new调用类的构造函数会执行如下操作

  1. 在内存中创建一个对象
  2. 这个新对象内部的[[ prototype ]]指针被赋值为构造函数的 prototype 属性
  3. 构造函数内部的this指向新对象
  4. 执行构造函数内部的代码(给新对象添加属性)
  5. 如果构造函数返回非空的对象,则返回该对象;否则返回刚创建的新对象。
class Person {
    // 添加到this的所有内容都会存在不同的实例中
    constructor(name,age){
        // ?? 空值合并操作符
        this.name = name ?? null
        this.age = age
    }
    // 在类块中定义的所有内容都会定义在类的原型上
    sayName(){
        console.log(this.name)
    }
}
let p = new Person('张三',18)
console.log(Person.prototype)
console.log('p.prototype访问:',p.prototype)
console.log('Object.getPrototypeOf()访问:',Object.getPrototypeOf(p))
p.sayName()
console.log(typeof Person) // function

image.png

实例、原型和类成员

1、实例成员

每次通过new调用类标识符时,都会执行类构造函数,在这个函数中可以为新创建的实例添加“自由”属性。每个实例都对应一个唯一的成员对象,这意味着所有成员都不会在原型上共享

class Person {
    constructor(age){
        this.name = new String('张三')
        this.friends = ['李四','王五']
    }
    sayName(){
        console.log(this.name)
    }
}
let p1 = new Person
let p2 = new Person
p1.sayName()
p2.sayName()
console.log(p1.name === p2.name) // false
console.log(p1.friends === p2.friends) // false

2、原型方法与访问器

为了在实例中共享方法,在类块中定义的方法作为原型方法

class Person{
    constructor(){
        this.locate = () => console.log('我在实例中')
    }
    locate(){
        console.log('我在原型上')
    }
}
let p = new Person()
p.locate()
Person.prototype.locate()

image.png

不能在类块中给原型添加原始值或对象作为成员数据,但可以在外面给类原型添加

class Person {
    name : '张三'
}

image.png

class Person { }
Person.prototype.name = '张三'
console.log(Person.prototype)

image.png

类也支持获取和设置访问器

class Person {
    constructor(){
        this._name = '张三'
    }
    set name(newName){
        this._name = newName
    }
    get name(){
        return this._name
    }
}
let p = new Person()
console.log(p._name) // 张三
p.name = '李四'
console.log(p._name) // 李四

image.png

静态类方法

静态方法常用于执行不特定于实例的操作,也不要求存在类的实例。与原型成员类似,每个类上只有一个静态成员,使用static关键字定义。在静态成员中,this引用类自身。只能通过类名调用静态方法

 class MyClass {
    static myStaticMethod() {
        console.log("我是静态方法");
    }

    myInstanceMethod() {
        MyClass.myStaticMethod(); // 通过类名调用静态方法
    }
}
      
const myObj = new MyClass();
myObj.myStaticMethod()// TypeError: myObj.myStaticMethod is not a function
myObj.myInstanceMethod(); // "我是静态方法"
MyClass.myStaticMethod(); // 通过类名调用静态方法

继承

es6支持单继承,使用extends关键字,就可以继承任何拥有construct和原型的对象。这意味着不仅可以继承一个类,也可以继承普通的构造函数

class Vehicle(){ 
    identifyPrototype(id){
        console.log(id,this)
    }
    static identifyClass(id){
        console.log(id,this)
    }
}

class Bus extends Vehicle{ } // 继承类
let b = new Bus()
console.log(b instanceof Bus) // true
console.log(b instanceof Vehicle)// ture

// 类和原型的方法都会带到派生类。this的值反映调用相应方法的实例或类
let v = new Vehicle()
b.identifyPrototype('bus')// bus, Bus{}
v.identifyClass('Vehicle')// Vehicle, Vehicle{}

Bus.identifyClass('bus')// bus , class Bus {}
Vehicle.identifyClass('Vehicle') Vehicle, class Vehicle{}

function Person{ }
class Enginner extends Person { } // 继承普通构造函数
let e = new Enginner()
console.log(e instanceof Enginner) // true
console.log(e instanceof Person)// ture

构造函数 和 super()

派生类通过super关键字引用他们的原型,super只能在派生类中使用。而且仅限于构造函数实例方法静态方法内部

构造函数

class Person {
    constructor(name){
        this.name = name
    }
    sayName(){
        console.log(this.name)
    }
}
class Child extends Person {
    constructor(name){
    // 不能在调用 super()之前调用this,否则会抛出错误
        super(name)
        console.log(this instanceof Person)
        console.log(this)
    }
}
let c = new Child('张三')
c.sayName()

image.png

静态方法

class Person{
    static sayHello(){
        console.log('调用超类静态方法')
    }
}
class Child extends Person { 
    static sayHello(){
        super.sayHello()
    }
}
Child.sayHello() // 调用超类静态方法

在使用super时注意的几个问题

  1. super只能在派生类构造函数和静态方法中使用,不能单独引用super
  2. 调用super会调用父类构造函数,并将实例赋值给this。可以传参
  3. 不能在调用super之前使用this
  4. 如果在派生类中显示的定义了构造函数,则必须要调用super或者返回一个对象