前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES6之class的继承

ES6之class的继承

作者头像
wade
发布2020-04-23 17:04:16
4860
发布2020-04-23 17:04:16
举报
文章被收录于专栏:coding个人笔记coding个人笔记

class语法为我们提供了构造函数的语法糖,响应的,也给我们提供了ES5通过原型链实现继承提供了extends关键字实现继承。继承这个概念对面后台应该也是非常常见。

通过extends继承,语法:

代码语言:javascript
复制
class User{}
class Son extends User{}

继承之后Son可以使用User类的所有属性和方法:

代码语言:javascript
复制
class User{
    constructor(a){
        this.a = a;
        this.b = 10;
    }
    eat(){
        console.log('user eat');
    }
}
class Son extends User{
    constructor(b, c){
      super(b);
      this.c = c;
    }
    sum(){
        console.log(this.a, this.b, this.c);
    }
}
var son = new Son(1, 2);
son.eat();//user eat
son.sum();//1 10 2

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

如果子类没有定义constructor方法,这个方法会被默认添加,需要注意的地方是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例。静态方法也会继承。

通过Object.getPrototypeOf获取父类:

代码语言:javascript
复制
class User{}
class Son extends User{}
console.log(Object.getPrototypeOf(Son));//class User{}

Super关键字有两个用法,一个是函数,一个是对象。当做函数的时候只能在子类的构造函数中使用,子类必须调用,也就是constructor里面,其他地方会报错:

代码语言:javascript
复制
class User{}
class Son extends User{
    eat(){
        super();
    }
}
//Uncaught SyntaxError: 'super' keyword unexpected here

作为对象的时候,普通方法super指向父类的原型对象,在静态方法中指向父类;

代码语言:javascript
复制
class User{
  constructor(){
      this.a = 1;
      this.b = 1;
  }
  eat(){
      console.log(this.b);//10
      return 2
  }
}
class Son extends User{
   constructor(){
       super();
       this.b = 10;
       this.c = 20;
       console.log(super.c);//undefined
       console.log(this.c);//20
   }
   talk(){
       console.log(super.a);//undefined
       console.log(super.eat());//2
   }
}
var son = new Son();
son.talk();

普通方法中,super指向父类原型对象(constructor里面是实例的属性),所以调用eat方法可以,a就获取不到。如果属性定义在父类的原型对象上,可以获取。子类调用super的时候,this指向当前子类的实例。对super赋值相当于为this赋值。

静态方法中,super指向父类,也就是User类:

代码语言:javascript
复制
class User{
    constructor(){
        this.a = 10;
    }
    static eat(val) {
        console.log('static', val);
    }
    eat(val) {
        console.log('instance', val);
    }
    static talk(){
        console.log(this.a);
    }
}
class Son extends User{
    constructor(){
        super();
        this.a = 20;
    }
    static eat(val) {
        super.eat(val);
    }
    eat(val) {
        super.eat(val);
    }
    static talk(){
        super.talk();
    }
}
Son.a = 30;
Son.talk();//30
Son.eat(1); // static 1
var son = new Son();
son.eat(2); // instance 2

子类Static eat方法super指向父类,所以调用父类static eat方法,子类普通方法eat指向父类原型对象,所以调用父类普通方法eat。子类静态方法super内部this指向当前子类,而不是实例或者原型对象,所以子类Son调用talk方法,输出的是30。

使用super必须指定是函数还是对象,否则报错。

类也是有prototype和__proto__属性的,相应的构成原型链:

子类的__proto__属性是构造函数的继承,指向父类

子类的prototype属性的__proto__属性,表示方法的继承,指向父类的prototype。

代码语言:javascript
复制
class User{}
class Son extends User{}
console.log(Son.__proto__ === User); // true
console.log(Son.prototype.__proto__ === User.prototype); // true

因为类的继承是通过setPrototypeOf。

子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型:

代码语言:javascript
复制
class User{}
class Son extends User{}
console.log(Son.__proto__ === User.__proto__); // false
console.log(Son.__proto__.__proto__ === User.__proto__); // true

原生的构造函数Boolean()、Number()、String()、Array()、Date()、Function()、RegExp()、Error()、Object()在ES5之前是无法继承的,ES6可以自定义原生数据结构:

代码语言:javascript
复制
class MyArray extends Array {
    constructor(...args) {
        super(...args);
    }
}
var arr = new MyArray();

Misin模式就是把多个对象合成一个新的对象,新对象有各个组成的接口:

代码语言:javascript
复制
var a = {}
var b = {}
var c = {...a, ...b}
阮大神提供了class的Mixin:
function mix(...mixins) {
    class Mix {
        constructor() {
            for (let mixin of mixins) {
                copyProperties(this, new mixin()); // 拷贝实例属性
            }
        }
    }
    for (let mixin of mixins) {
        copyProperties(Mix, mixin); // 拷贝静态属性
        copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
    }
    return Mix;
}
function copyProperties(target, source) {
    for (let key of Reflect.ownKeys(source)) {
        if ( key !== 'constructor'
            && key !== 'prototype'
            && key !== 'name'
        ) {
            let desc = Object.getOwnPropertyDescriptor(source, key);
            Object.defineProperty(target, key, desc);
        }
    }
}

使用:

代码语言:javascript
复制
class DistributedEdit extends mix(Loggable, Serializable) {// ...}

建议可以使用了看看打印的数据。

(完)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 coding个人笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档