神族九帝's blog 神族九帝's blog
首页
网盘 (opens new window)
线报 (opens new window)
商城 (opens new window)
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 基础篇
  • 进阶篇
  • 高级篇
  • 计算机基础
  • 高频考点
  • 精简题
  • 综合问题
  • 复习题
  • vue
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • 更多
  • 网站
  • 资源
  • Vue资源
  • 收藏的一些API
  • 未来要做的事
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 导航
GitHub (opens new window)

神族九帝,永不言弃

首页
网盘 (opens new window)
线报 (opens new window)
商城 (opens new window)
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 基础篇
  • 进阶篇
  • 高级篇
  • 计算机基础
  • 高频考点
  • 精简题
  • 综合问题
  • 复习题
  • vue
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • 更多
  • 网站
  • 资源
  • Vue资源
  • 收藏的一些API
  • 未来要做的事
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 导航
GitHub (opens new window)
  • 复习指导

  • HTML

  • CSS

  • JavaScript

    • 思维导图
    • 数据类型
    • 隐式类型转换
    • 闭包
    • 原型和原型链
    • 继承
      • js 如何实现继承
        • 借助 call
        • 借助原型链
        • 前两种结合
        • 组合继承的优化 1
        • 组合继承的优化 2(推荐)
        • ES6 的 extends 被编译后的 JavaScript 代码
      • 参考链接
    • 数组扁平化flat
    • new操作符做了什么
    • 数组去重性能
    • 防抖与节流函数
    • 深浅拷贝
    • Event Loop
    • 数组方法和类数组
    • 数组排序
    • 异步编程
    • 获取URL参数
    • 模块规范
    • tree-shaking的原理
    • 隔离沙箱
  • 设计模式

  • 浏览器

  • 手写系列

  • Vue

  • Webpack

  • Http

  • 前端优化

  • 项目

  • 面试真题

  • 算法

  • 精选文章

  • 八股文

  • 前端工程化

  • 面试题
  • JavaScript
wu529778790
2018-06-15

继承

# js 如何实现继承

  • 借助 call
  • 借助原型链
  • 前两种结合
  • 组合继承的优化 1
  • 组合继承的优化 2(推荐)
  • ES6 的 extends 被编译后的 JavaScript 代码

# 借助 call

function Parent() {
  this.name = "parent";
}
function Child() {
  Parent.call(this);
  this.type = "child";
}
console.log(new Child());

问题:父类对象中的方法子类无法继承,只能拿到父类的属性值

# 借助原型链

function Parent() {
  this.name = "parent";
  this.play = [1, 2, 3];
}
function Child() {
  this.type = "child";
}
Child2.prototype = new Parent();

console.log(new Child());

问题:引用类型指向的是同一个内存地址

# 前两种结合

function Parent() {
  this.name = "parent";
  this.play = [1, 2, 3];
}

function Child() {
  this.type = "child";
  Parent.call(this);
}
Child.prototype = new Parent();

var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play);

问题:Parent 的构造函数会多执行了一次(Child.prototype = new Parent();)

# 组合继承的优化 1

function Parent() {
  this.name = "parent";
  this.play = [1, 2, 3];
}

function Child() {
  Parent.call(this);
  this.type = "child";
}

Child.prototype = Parent.prototype;

问题:将父类原型对象直接给到子类,父类构造函数只执行一次,而且父类属性和方法均能访问

但是子类实例的构造函数是 Parent4,显然这是不对的,应该是 Child4

var s3 = new Child();
var s4 = new Child();
console.log(s3);

20210615193516

# 组合继承的优化 2(推荐)

这是最推荐的一种方式,接近完美的继承,它的名字也叫做寄生组合继承

function Parent() {
  this.name = "parent";
  this.play = [1, 2, 3];
}
function Child() {
  Parent5.call(this);
  this.type = "child";
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

# ES6 的 extends 被编译后的 JavaScript 代码

es6 的 extends 经过 babel 编译之后的代码

function _possibleConstructorReturn(self, call) {
  // ...
  return call && (typeof call === "object" || typeof call === "function")
    ? call
    : self;
}

function _inherits(subClass, superClass) {
  // ...
  //看到没有
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true,
    },
  });
  if (superClass)
    Object.setPrototypeOf
      ? Object.setPrototypeOf(subClass, superClass)
      : (subClass.__proto__ = superClass);
}

var Parent = function Parent() {
  // 验证是否是 Parent 构造出来的 this
  _classCallCheck(this, Parent);
};

var Child = (function(_Parent) {
  _inherits(Child, _Parent);

  function Child() {
    _classCallCheck(this, Child);

    return _possibleConstructorReturn(
      this,
      (Child.__proto__ || Object.getPrototypeOf(Child)).apply(this, arguments)
    );
  }

  return Child;
})(Parent);

核心是_inherits 函数,可以看到它采用的依然也是第五种方式————寄生组合继承方式,同时证明了这种方式的成功。不过这里加了一个 Object.setPrototypeOf(subClass, superClass),这是用来干啥的呢?

答案是用来继承父类的静态方法。这也是原来的继承方式疏忽掉的地方。

继承的最大问题在于:无法决定继承哪些属性,所有属性都得继承。组合,这也是当今编程语法发展的趋势,比如 golang 完全采用的是面向组合的设计方式

# 参考链接

  • https://sanyuan0704.top/my_blog/blogs/javascript/js-base/006.html (opens new window)
编辑 (opens new window)
上次更新: 2022/05/24, 14:27:28
原型和原型链
数组扁平化flat

← 原型和原型链 数组扁平化flat→

最近更新
01
好玩的docker
07-04
02
我的第一个NFT
07-03
03
海外迅雷
06-01
更多文章>
Power by vuepress | Copyright © 2015-2023 神族九帝
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×