es5继承和es6继承中静态方法、静态属性的差别

最近在看vue的源码,其中有一部分牵扯到了继承,看到es5中静态方法的"继承"是这样写的vue

const Sub = function VueComponent (options) {
        this._init(options)
      }
      Sub.prototype = Object.create(Super.prototype)
      Sub.prototype.constructor = Sub
        ...
      Sub.extend = Super.extend
      Sub.mixin = Super.mixin
      Sub.use = Super.use
复制代码

es5的继承你们都知道(经过原型链实现原型属性的继承,经过构造函数实现实例属性的继承),但代码中静态方法是直接从父类赋给子类的,这就想到的一个问题?静态方法没有继承吗?带着这个问题研究了一下静态方法在es5继承中和es6继承中的差别es6

es5中静态方法的继承

// 定义父类
    function Super(name, age) {
      this.name = name;
      this.age = age;
    };
    Super.prototype.sayName = function() {
      return this.name;
    };
    // 定义属性
    Super.num = 1;
    // 定义静态方法
    Super.sayWord = function(word) {
      return word;
    };
    // 定义子类
    function Sub(name, age, sex) {
      // 继承实例属性
      Super.call(this, name, age);
      this.sex = sex;
    }
    // 继承父类的原型方法+原型属性
    Sub.prototype = Object.create(Super.prototype);
    Sub.prototype.constructor = Sub;
    
    var instance = new Sub('张三', '18', '男');
复制代码

分别打印出来看下结果:函数

console.log(Super.sayWord('hello world'));
    // print TypeError: Sub.sayWord is not a function
    
    console.log(Sub.sayWord('hello world'));
   // print TypeError: Sub.sayWord is not a function
    
    console.log(instance.sayWord('hello world'));  // 实例是没法获取到静态方法的
    // print instance.sayWord is not a function
复制代码

静态属性和静态方法相似,你们能够自行验证,经过上面的咱们能够得出下面的结论: es5的类继承:子类是没法继承父类的静态属性和静态方法的,只是经过传递测试

其中有个须要注意的地方:静态方法没办法获取到this,因为JavaScript中的类也是一个对象,静态方法至关因而这个类对象的一个属性方法,可是this指的是当前实例对象而不是类对象,因此是没法取到的,下面看下es6中的ui

es6中静态方法的继承

class Super {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayName() {
    return this.name;
  }

  static sayWord(word) {
    return word;
  }

  static get num() {
    return this._num; // 由于类也是一个对象 因此_num 只是这个类上的属性 并不是实例属性
  }

  static set num(n) {
    this._num = n;
  }
}

class Sub extends Super {
  constructor(name, age, sex) {
    super(name, age);
    this.sex = sex;
  }
}

const instance = new Sub('张三', '18', '男');
复制代码

下面咱们分别看下静态方法和静态属性this

console.log(Super.sayWord('hello world'));
// print hello world
console.log(Sub.sayWord('hello world'));
// print hello world
console.log(instance.sayWord('hello world'));
// print TypeError: instance.sayWord is not a function
复制代码

能够看出es6继承中,静态方法被继承下来,这点与es5仍是有差别的,再看静态属性, es6中的静态属性能够直接[类名].[属性名]这样的定义,也能够如上面那样定义(get,set),只是get,set这样的定义咱们能够更好进行的控制es5

Super.num = 3;
console.log(Super.num);
// print 3
console.log(Sub.num);
// print 3
复制代码

看的出,静态属性也被继承了,可是这样也有问题,当静态属性是引用类型时,子类和父类指向的同一个地址,父类若是发生变化子类也会跟着变化,这是咱们不但愿看到的spa

Super.num = [];

Sub.num.push(1);
console.log(Super.num);
// print [1]
console.log(Sub.num);
// print [1]

Super.num.push(2);
console.log(Super.num);
// print [1,2]
console.log(Sub.num);
// print [1,2]
复制代码

咱们修改下静态属性num的get方法,使其只获取本身当前类的值,而非继承的值prototype

static get num() {
    return this.hasOwnProperty('_num') ? this._num : undefined;
  }
复制代码

再测试一下:code

Super.num = [];
// Sub.num.push(1);
// print TypeError: Cannot read property 'push' of undefined 由于Sub.num获得的是 undefined
Sub.num=1;
console.log(Super.num);
// print []
console.log(Sub.num);
// print 1
Super.num.push(2);
console.log(Super.num);
// print [2]
console.log(Sub.num);
// print 1
复制代码

能够得出:es6中的静态方法和静态属性均可以被继承下来的,只是静态属性的继承须要稍做处理,不然就被共享了

下面咱们再总结下:

  1. es5和es6实现继承的方式是不一样的,前者经过原型链实现对父类原型方法、原型属性的继承,经过构造函数的调用实现对实例方法,实例属性的调用,后者经过extends关键字实现继承
  2. es5中静态方法、静态属性是没法经过继承下来的,只能经过赋值传递,如最开始的demo,但es6中则是能够的
相关文章
相关标签/搜索