ES5和ES6继承

本文探讨了ES5的七种继承方案,包括原型链、构造函数、组合继承等,以及ES6的类继承(extends)。分析了各种继承方式的优缺点,如原型链继承可能导致引用类型被篡改,构造函数继承无法继承原型属性,组合继承可能导致属性重复。同时,解释了构造函数调用模式中this的指向,并举例说明了ES6 extends关键字的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES5常用七种继承方案和ES6的类继承,有八种继承方案。

ES5:

原型链继承、借用构造函数继承、组合继承、
原型式继承、寄生式继承、寄生组合式继承、
混入方式继承多个对象

ES6:

类继承extends

1.原型链继承

原型链继承就是SuperType的原型指向SuperType的实例,那么就可以继承SuperType原型链上方法。

继承的本质就是复制,即重写原型对象,代之以一个新类型的实例。

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

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

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

// 这里是关键,创建SuperType的实例,并将该实例赋值给SubType.prototype
SubType.prototype = new SuperType(); 

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

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

在这里插入图片描述
原型链方案存在的缺点:多个实例对引用类型的操作会被篡改。

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

SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"

var instance2 = new SubType(); 
alert(instance2.colors); //"red,blue,green,black"

2.借用构造函数继承

使用父类的构造函数来增强子类实例,等同于复制父类的实例给子类(不使用原型)

function  SuperType(){
    this.color=["red","green","blue"];
}
function  SubType(){
    //继承自SuperType
    SuperType.call(this);
}
var instance1 = new SubType();
instance1.color.push("black");
alert(instance1.color);//"red,green,blue,black"

var instance2 = new SubType();
alert(instance2.color);//"red,green,blue"

核心代码是SuperType.call(this),创建子类实例时调用SuperType构造函数,于是SubType的每个实例都会将SuperType中的属性复制一份。

缺点:
1.只能继承父类的实例属性和方法,不能继承原型属性/方法
2.无法实现复用,每个子类都有父类实例函数的副本,影响性能

下面我们介绍下SuperType.call(this)的意思

我们需要了解:
1.函数的调用模式
2.this

函数的调用模式

1.
var name = 'qianlong';
var showName = function () {
  console.log(this.name);
  console.log(this === window);
};

showName();   //qianlong true

2.
var name = 'qianlong';
var showName = function () {
  console.log(this.name);
  console.log(this === window);
};

showName.call();   //qianlong true

3.
var name = 'qianlong';
var showName = function () {
  console.log(this.name);
  console.log(this === window);
};

showName.call(undefined);   //qianlong true
showName.call(null);   //qianlong true
showName.call({});   //undefined false

得出结论:
普通的函数调用和showName.call()形式得到结果都是一样的,函数内的this指向的是window对象(当然这是在浏览器以及非严格模式下),如果而当第一个参数不为空或者undefined以及null的时候,这个时候函数内部的this就是指向传进来的第一个参数。

new中this指的是什么呢


var Person = function () {
  this.name = 'qianlong';
  this.sex = 'boy';
  console.log(this);
};

var p1 = new Person();

你发现了啥? 使用new来调用函数的时候,内部的this就是指向,最终生成的那个对象.

此时,我们再看代码:

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

function SubType () {
  SuperType.call(this); // 这里的this就是指向new SubType() 后生成的对象。
}

var instance1 = new SubType();
// SubType中的this这个时候可以理解为instance1共同指向的一个对象的引用
{
 colors: [
   'red',
   'blue',
   'green'
 ]
}

call 方法就是把目标方法绑定参数对象去执行。SuperType.call(this) 注意这里的this就是SubType实例,此时也就是相当于执行 SubType实例.SuperType().

参考文章:https://segmentfault.com/q/1010000007648841

3.组合继承

组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。

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

function SubType(name, age){
  // 继承属性
  // 第二次调用SuperType()
  SuperType.call(this, name);
  this.age = age;
}

// 继承方法
// 构建原型链
// 第一次调用SuperType()
SubType.prototype = new SuperType(); 
// 重写SubType.prototype的constructor属性,指向自己的构造函数SubType
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

在这里插入图片描述

缺点:
1.第一次调用SuperType():给SubType.prototype写入两个属性name,color。
2.第二次调用SuperType():给instance1写入两个属性name,color。

实例对象instance1上的两个属性就屏蔽了其原型对象SubType.prototype的两个同名属性。所以,组合模式的缺点就是在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法。

4.

5.

6.

7.

8.ES6类继承extends

extends关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。其中constructor表示构造函数,一个类中只能有一个构造函数,有多个会报出SyntaxError错误,如果没有显式指定构造方法,则会添加默认的 constructor方法,使用例子如下。

class Rectangle {
    // constructor
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
    
    // Getter
    get area() {
        return this.calcArea()
    }
    
    // Method
    calcArea() {
        return this.height * this.width;
    }
}

const rectangle = new Rectangle(10, 20);
console.log(rectangle.area);
// 输出 200

-----------------------------------------------------------------
// 继承
class Square extends Rectangle {

  constructor(length) {
    super(length, length);
    
    // 如果子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
    this.name = 'Square';
  }

  get area() {
    return this.height * this.width;
  }
}

const square = new Square(10);
console.log(square.area);
// 输出 100

extends继承的核心代码如下,其实现和上述的寄生组合式继承方式一样

function _inherits(subType, superType) {
  
    // 创建对象,创建父类原型的一个副本
    // 增强对象,弥补因重写原型而失去的默认的constructor 属性
    // 指定对象,将新创建的对象赋值给子类的原型
    subType.prototype = Object.create(superType && superType.prototype, {
        constructor: {
            value: subType,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    
    if (superType) {
        Object.setPrototypeOf 
            ? Object.setPrototypeOf(subType, superType) 
            : subType.__proto__ = superType;
    }
}

更多详细可以参考文章:
https://juejin.im/post/5bcb2e295188255c55472db0
https://www.cnblogs.com/annika/p/9073572.html
https://segmentfault.com/a/1190000003973606

https://segmentfault.com/a/1190000015727237#articleHeader10
https://segmentfault.com/a/1190000015216289
https://segmentfault.com/a/1190000014476341
http://keenwon.com/1524.html
https://github.com/noahlam/articles/blob/master/JS中的原型对象.md
https://www.jianshu.com/p/342966fdf816
https://juejin.im/entry/5bbf51015188255c3a2d6965
https://juejin.im/post/5bd7f8ed5188252a784d2201#comment
https://zhuanlan.zhihu.com/p/32502909

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值