Skip to content

JS中的继承专题(ES6) #27

Open
@Reaper622

Description

@Reaper622

Class 的定义

ES6中的class本质还是函数,即类的数据类型还是函数,类本身指向构造函数。

class Person {
    //...
}

typeof Person // 'function'
Person === Person.prototype.constructor // true
// 另一种定义class的方式是表达式形式
const ThePerson = class {
    //...
}

注意class本身不具有变量提升,并存在暂时性死区

const reaper = new Person('reaper'); // ReferenceError: Cannot access 'Person' before initialization
class Person {
    constructor(name) {
        this.name = name;
    }
}

并且,class内默认开启严格模式,class内的所有方法,包括静态方法和实例方法,都是不可枚举的。「enumerable: false」

// 引用一个未声明的变量
function Bar() {
  this.bar = 42;
}
Bar.answer = function() {
  return 42;
};
Bar.prototype.print = function() {
  console.log(this.bar);
};
const barKeys = Object.keys(Bar); // ['answer']
const barProtoKeys = Object.keys(Bar.prototype); // ['print']

class Foo {
  constructor() {
    this.foo = 42;
  }
  static answer() {
    return 42;
  }
  print() {
    console.log(this.foo);
  }
}
const fooKeys = Object.keys(Foo); // []
const fooProtoKeys = Object.keys(Foo.prototype); // []

ES5中,构造函数可以不通过new执行,从而会给全局对象添加上属性,在ES6的class中,必须通过new调用,否则无法执行。

继承

在ES5中,我们通过子类寻找父类的方式是

function Super() {}
function Sub() {}

Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
Sub.__proto__ === Function.prototype // true

与ES5不同的是,ES6的继承子类可以直接通过__proto__找到父类。

class Super {}
class Sub extends Super {}
// 表示构造函数的继承,总是指向父类
Sub.__proto__ === Super; // true
// 表示方法的继承,总是指向父类的原型
Sub.prototype.__proto__ === Super.prototype; // true

底层原因是babel在解析上面的代码时会解析为:

Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.__proto__ = Super

this

类方法的内部如果含有this,他就默认指向类的实例,但是不可单独使用类内的方法,否则会产生this指向错误。

一种方法时在构造方法中绑定this,这样就不会产生this指向错误。【React类组件内部】

class Person {
    constructor(name) {
        this.name = name;
        this.hello = this.hello.bind(this);
    }
    hello() {
        return this.name;
    }
}
let man = new Person('reaper');
let foo = man.hello
foo() // 'reaper'

super

我们在类的继承中,在子类的构造函数中需要使用到super()来执行父类的构造函数。

class Super() {
    constructor(name) {
        this.name = name;
    }  
}
class Sub() {
    constructor(name, age) {
        super(name); // 使用super
        this.age = age;
    }
}

如果不使用super,那么构建实例时会报错,这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。

在ES5的继承中,继承的实质是先创建子类的实例对象this,之后向子类的实例对象this上添加父类的方法Parent.call(this),而ES6的继承则是先创建父类的实例对象,然后调用子类的构造函数进行对this的修改,因此需要先调用super

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions