从我之前的一篇笔记对象的继承中, 我们可以知道JS的继承方式依赖原型链,而比较好的继承方式是寄生组合式继承
先来温习下什么是寄生组合式继承
function Rectangle(length, width) {
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function() {
return this.length * this.width;
};
function Square(length) {
Rectangle.call(this, length, length);
// 1 调用父类构造函数
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
value:Square,
enumerable: true,
writable: true,
configurable: true
}
});
// 2 Object.create会在内部创建一个空对象来连接两个原型对象, 再手动将constructor指向自身
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
ES6之前的继承方式,对原型链理解不够深透的话很容易混乱ES6推出class这个类之后,一切都变得简单(再次提醒:class只是语法糖,本质还是构造和原型继承的一些组合首先我们将继承其他类的的类称为派生类(derived classes), 再来看看上面的例子, 利用class如何轻松实现
class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
class Square extends Rectangle {
constructor(length) {
// 与 Rectangle.call(this, length, length) 相同
super(length, length);
}
}
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
console.log(Square.prototype.constructor === Square) // true
实现继承只需要两步
class上extends继承父类super()super也是ES6中的内容,它是指向当前对象的原型的一个指针,实际上就是Object.getPrototypeOf(this)的值。
根据上面的例子我们来看下
Object.getPrototypeOf(Square) === Rectangle // true
那super(length, lenght)应该是Rectangle(lenght, length)才对啊,其实在ES6中真正出现了方法的概念,从前只能说是一个函数属性, 在方法中会有一个内部属性[[HomeObject]]任何对super的引用都会使用[[HomeObject]]属性来判断要做什么。第一步是在[[HomeObject]]上调用Object.getPrototypeOf()来获取对原型的引用;最后,创建this绑定并调用该方法的对象。因此是Rectangle.call(this, length, length)
注意点:
extends就必须在构造器中调用super()super必须要在this前面super():return返回一个对象,不能是number等基本数据类型,否则return的是thisclass Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
// 不传super()
class Square extends Rectangle {
constructor(length) {
}
}
let s1 = new Square(3) //Uncaught ReferenceError: Must call super constructor in derived class before accessing ‘this‘ or returning from derived constructorat new Square
// 报错 必须在访问this前面调用super构造器或者在返回一个新的Square实例对象必须调用super构造器
// 直接不传入构造器
class Square extends Rectangle {}
let s2 = new Square(3, 4)
console.log(s2.getArea()) //12
console.log(s2.width) // 4
console.log(s2.length) // 3
// 其实默认调用了构造器
//class Square extends Rectangle {
// constructor(...args) {
// super(...args)
// }
//}
// 返回一个对象
class Square extends Rectangle {
constructor(length) {
return {}
}
}
let s2 = new Square()
console.log(s2 instanceof Square) // false
其实从之前的super就能看出个大概了
Object.getPrototypeOf(Square) === Rectangle // true
因此Rectangle的静态成员自然可以被Square访问到
Rectangle.create = function(l, w) {
return new Rectangle(l, w)
}
console.log(‘create‘ in Square) // true
console.log(Square.hasOwnProperty(‘create‘)) // false
其实只要一个表达式能够返回一个具有[[Construct]]属性的以及原型的函数,就可以对其实使用extends
一般来说,对象的原型会在通过构造器或Object.create() 方法创建该对象时被指定。而[[Construct]]只有箭头函数没有
因此一下几种情况都是可以的
function Parent() {
}
class Child extends Parent {
}
console.log(Child.prototype.__proto__ === Parent.prototype) // true
console.log(Child.__proto__ === Parent) // true
let AreaMixin = {
getArea() {
return this.length * this.width;
}
};
function mixin(...mixins) {
var base = function() {};
Object.assign(base.prototype, ...mixins);
return base;
}
class Square extends mixin(AreaMixin, SerializableMixin) {
constructor(length) {
super();
this.length = length;
this.width = length;
}
}
var x = new Square(3);
console.log(x.getArea()); // 9
console.log(x.serialize()); // "{"length":3,"width":3}"原文:https://www.cnblogs.com/guanine/p/9348565.html