乐趣区

ES6-class-extends

继承 inherit

class 是对原型继承的一种语法糖的包装。那相对于原型继承,它有什么优点呢?
我们来先看一个典型的基于原型链继承的例子。部分内容来自“Javascript 高级程序设计”

function SuperType() {this.property = true;}

SuperType.prototype.getSuperValue = function() {return this.property;}

function SubType() {this.subProperty = false;}

SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function() {return this.subProperty;}

var instance = new SubType();
console.log(instance.getSuperValue());  // true
console.log(instance instanceof Object);  // true
console.log(instance instanceof SuperType);  // true
console.log(instance instanceof SubType);  // true

问题,当包含引用类型的值。

function SuperType() {this.colors = ["red", "blue", "green"];
}

function SubType() {}

SubType.prototype = new SuperType();


var instance = new SubType();
instance.colors.push("black");
var instance1 = new SubType();
instance1.colors.push("white");
console.log(instance.colors);  // ['red', 'blue', 'green', 'black', 'white']
console.log(instance1.colors);  // ['red', 'blue', 'green', 'black', 'white']

解决方案:

  • 借用构造函数
function SuperType() {this.colors = ["red", "blue", "green"];
}

function SubType() {SuperType.call(this);
}

SubType.prototype = new SuperType();


var instance = new SubType();
instance.colors.push("black");
var instance1 = new SubType();
instance1.colors.push("white");
console.log(instance.colors);
console.log(instance1.colors);
  • 组合继承
function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function() {console.log(this.name);
}

function SubType(name, age) {SuperType.call(this, name);
   this.age = age;
}

SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {console.log(this.age);
}
  • 寄生组合式继承
function object(o) {function F() {}
    F.prototype = o;
    return new F();}

function inheritPrototype(subType, superType) {let prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function() {console.log(this.name);
}

function SubType(name, age) {SuperType.call(this, name);
   this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function() {console.log(this.age);
}
var instance = new SubType("Tom", 70);
instance.colors.push("black");
var instance1 = new SubType("Jerry", 69);
instance1.colors.push("white");
console.log(instance.colors);
console.log(instance.sayName());
console.log(instance.sayAge());
console.log(instance1.colors);
console.log(instance1.sayName());
console.log(instance1.sayAge());

MDN 原型链继承
(欠图一张)

extends

从 es5 来说,实现对象的继承,还是相当麻烦的。而 extends 关键字的出现,使继承变得简单,原型会自动进行调整,super()/super 关键字可以访问父类的构造方法和属性。

class Animal {constructor(name) {this.name = name;}
  
  speak() {console.log(this.name + 'makes a noise.');
  }
}

class Dog extends Animal {speak() {console.log(this.name + 'barks.');
  }
}

var d = new Dog('Mitzie');
d.speak();// 'Mitzie barks.'

分析:Dog 类没有构造函数,这样合理吗?

// 等价于上个类定义
class Dog extends Animal {constructor(name) {super(name)
  }
  speak() {console.log(this.name + 'barks.');
  }
}

super() 方法调用注意:

  • 只可在以 extends 实现的派生类中的 constructor 方法中调用,在非派生类或方法中直接调用,会报错。
  • 在 constructor 中访问 this 之前,一定要先调用 super(), 因为它负责初始化 this, 如果在 super() 调用之前尝试访问 this,会报错。
  • 如果不想调用 super(),则唯一的方法是让类的 constructor() 返回一个对象。

类方法遮蔽

说明:派生类中的方法总会覆盖基类中的同名方法。

class Animal {constructor(name) {this.name = name;}
  
  speak() {console.log(this.name + 'makes a noise.');
  }
}

class Dog extends Animal {speak() {console.log(this.name + 'barks.');
  }
}
// 基类中的 speak() 方法被覆盖 

静态类成员继承

说明:如果基类有静态成员,那么这些静态成员在派生类中也可用。

class Animal {constructor(name) {this.name = name;}
    
    speak() {console.log(this.name + 'makes a noise.');
    }
    static create(name) {return new Animal(name);
    }
  }
  
  class Dog extends Animal {speak() {console.log(this.name + 'barks.');
    }
  }

  let a1 = Animal.create("Monkey");
  let a2 = Dog.create("BeijinDog");
  console.log(a1 instanceof Animal);  // true
  console.log(a2 instanceof Animal);  // true
  console.log(a2 instanceof Dog);  // false 这个是不是很意外?

派生自表达式的类

内建对象继承

Symbol.species

constructor 中 new.target

退出移动版