资讯专栏INFORMATION COLUMN

JavaScript 继承的那些事

singerye / 3295人阅读

摘要:实际上也就是在原型链继承的代码中添加在子类的构造函数中调用父类构造函数。寄生组合式继承在指定子类的原型的时候不必调用父类的构造函数,而是直接使用创建父类原型的副本。

原本地址:http://www.ahonn.me/2017/01/2...

众所周知,JavaScript 的继承是实现继承,而没有 Java 中的接口继承。这是因为 JavaScript 中函数没有签名,而实现继承依靠的是原型链来实现的。

原型链继承

JavaScript 中通过修改对象原型指向的对象来实现继承,即是将一个对象的原型指向要继承的对象实例,从而实现继承对象的属性及方法。

function SuperType() {
  this.type = "super";
}

SuperType.prototype.getType() {
  return this.type;
}

function SubType() {
  this.type = "sub";
}

SubType.prototype = new SuperType();

var sub = new SubType();
console.log(sub.getType()); // "sub"
原型链继承的不足

实际上,上面的代码还缺少一句代码,我们将 SubType 的原型指向了 SuperType 的实例,即SubType.prototype.constructor 会返回 SuperType 而不是 SubType,使用 instanceof 操作符返回的将是 SuperType。所以需要将 SubType.prototype.constructor 重新指向 SubType

// ...
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
// ... 

但即使是这样,原型链继承依然有两点问题:原型中的实例引用类型属性会在所有对象实例中共享,无法想 Java 的继承一样向父类的构造函数中传递参数。

其他继承方式

由于原型链继承存在一些不足,为了解决这些不足,JavaScript 中还有其他的几种继承的方式。

借用构造函数

因为原型链无法传递参数到父类的构造函数中,因此出现了这种叫做借用构造函数的技术。顾名思义,即是借用父类的构造函数在子类中进行调用。

function SuperType() {
  // ...
}

function SubType() {
  SuperType.call(this); // <- 执行父类构造函数
  // ...
}

借用构造函数虽然解决了构造函数传参的问题,但是当父类拥有方法时每个子类的实例都会拥有独立的方法,这个问题与多带带使用构造函数模式定义类型的时候相同。

组合继承

类比使用构造函数模式定义类型时的解决方法(组合构造函数模式与原型模式),继承时的解决方法也类似。即组合原型链继承和借用构造函数,属性由借用构造函数的方式继承,方法由原型链继承。

实际上也就是在原型链继承的代码中添加在子类的构造函数中调用父类构造函数。

function SuperType() {
  this.type = "super";
}

SuperType.prototype.getType() {
  return this.type;
}

function SubType() {
  SuperType.call(this);
  this.type = "sub";
}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
寄生组合式继承

组合继承是常用的继承方式,但是同样的也是有不足之处:调用了两次父类的构造函数,一次在子类构造函数中调用父类构造函数,一次在实例父类对象赋值给子类的原型。

寄生组合式继承在指定子类的原型的时候不必调用父类的构造函数,而是直接使用 Object.create() 创建父类原型的副本。

function SuperType() {
  // ...
}

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

SubType.prototype = Object.create(SuperType.prototype); // 直接使用父类原型创建副本
SubType.prototype.constructor = SubType;
ES6 中的继承

ES6 引入了 class 关键子,可以像其他语言中一样使用 extends 关键字来继承。虽然能够使用 extends 实现继承,但实际上内部还是基于原型。

class SubType extends SuperType {
  constructor() {
    super();
    // ...
  }

  // ...
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81364.html

相关文章

  • JavaScript面向对象那些

    摘要:委托上面的代码结合了构造函数和原型两种方式去创建对象,首先聊聊构造函数构造函数构造函数本质上还是函数,只不过为了区分将其首字母大写了而已。注意注释掉的代码是自动执行的,但这并不是构造函数独有的,每个函数在声明时都会自动生成。 首先看看下面两个1+1=2的问题: 问题一:为什么改变length的值,数组的内容会变化? var arr = [1]; arr.length = 3; aler...

    王伟廷 评论0 收藏0
  • 继承那些

    摘要:借用构造函数继承针对上面的继承方法的缺点,开发人员使用一种叫做借用构造函数的技术,也就是我们平时说的跟继承。 继承是 OO 语言中一个最为津津乐道的概念,许多 OO 语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。由于函数没有签名,在 ECMAScript 中无法实现接口继承。ECMAScript 只支持实现继承而且实现继承主要是依靠原型...

    CoyPan 评论0 收藏0
  • 【面试】Java基础那些-Two

    摘要:前言面试中对于技术职位,一般分笔试与面谈,如果面试官的一些小问题你可以立马找到对应的知识点扩展开来,那么这就是你的优势,本系列将讲述一些面试中的事,不会很详细,但是应该比较全面吧。 前言 面试中对于技术职位,一般分笔试与面谈,如果面试官的一些小问题你可以立马找到对应的知识点扩展开来,那么这就是你的优势,本系列将讲述一些java面试中的事,不会很详细,但是应该比较全面吧。 主要内容 pa...

    you_De 评论0 收藏0
  • 2018 浅谈前端面试那些

    摘要:声明的变量不得改变值,这意味着,一旦声明变量,就必须立即初始化,不能留到以后赋值。 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总 1.HTML HTML5新特性,语义化浏览器的标准模式和怪异模式xhtml和html的区别使用data-的好处meta标签canvasHTML废弃的标签IE6 bug,和一些定位写法css js放置位置和原因...

    LiuRhoRamen 评论0 收藏0
  • 2018 浅谈前端面试那些

    摘要:声明的变量不得改变值,这意味着,一旦声明变量,就必须立即初始化,不能留到以后赋值。 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总 1.HTML HTML5新特性,语义化浏览器的标准模式和怪异模式xhtml和html的区别使用data-的好处meta标签canvasHTML废弃的标签IE6 bug,和一些定位写法css js放置位置和原因...

    stormgens 评论0 收藏0

发表评论

0条评论

singerye

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<