IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> js的继承方式 -> 正文阅读

[JavaScript知识库]js的继承方式

确定原型和实列的关系

  • instance instanceof ClassName
  • ClassName.prototype.isPrototypeOf(instance)

1. es6的extends

清晰方便

// es6继承
class Point {
  x;
  y;
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  print() {
    console.log(`Point:(${this.x},${this.y})`);
  }
}

class ColorPoint extends Point {
  color;
  constructor(x, y, color) {
    // 必须调用父类构造函数
    super(x, y);
    this.color = color;
  }

  // 覆盖父类方法
  print() {
    console.log(`ColorPoint:(${this.x},${this.y}) ${this.color}`);
  }
}

const p = new Point(1, 2);
p.print(); // Point:(1,2)

const cp = new ColorPoint(3, 4, "red");
cp.print(); // ColorPoint:(3,4) red


2. 原型链继承

通过让子类的prototype等于父类的实例来实现继承

两个缺点

1. 因为所有子类的__proto__指向是同一个父类的实例,这会导致对这个实例引用类型的修改,作用于所有的子类上

2. 创建子类实例的时候,不能向父类的构造函数传递参数

function Point(x, y) {
  this.x = x;
  this.y = y;
  this.arr = [x, y];
}
Point.prototype.print = function () {
  console.log(`Point:(${this.x},${this.y})`);
};

function ColorPoint(color) {
  this.color = color;
}
// 将子类的prototype改成父类的实例
ColorPoint.prototype = new Point(1, 2);
ColorPoint.prototype.print = function () {
  console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};

const cp = new ColorPoint("red");
cp.print(); // ColorPoint:(1,2) red [1,2]

const cp2 = new ColorPoint("blue");
cp2.x = 233; // 这种操作只是在cp2增加了一个x属性,不会影响cp的x
cp2.arr[0] = 10086; // 这种操作修改了父类的那个实例的arr的值,会影响到cp
cp2.print(); // ColorPoint:(233,2) blue [10086,2]
cp.print(); // ColorPoint:(1,2) red [10086,2]


3.借用构造函数(伪造对象 经典继承)

在子类的构造函数中,使用apply(入参是是数组)或者call(入参是一个个)方法调用父类的构造函数

缺点

因为实际只是借用了父类的构造函数,所以定义在父类原型中的方法,子类没有继承。instanceof检查也会是false

function Point(x, y) {
  this.x = x;
  this.y = y;
  this.arr = [x, y];
}
Point.prototype.print = function () {
  console.log(`Point:(${this.x},${this.y})`);
};

function ColorPoint(x, y, color) {
  Point.call(this, x, y);
  this.color = color;
}
ColorPoint.prototype.printColor = function () {
  console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};

const cp = new ColorPoint(1, 2, "red");
// cp.print(); // 没有继承prit方法,报错
cp.printColor(); // ColorPoint:(1,2) red [1,2]

console.log(cp instanceof Point); // false
console.log(cp instanceof ColorPoint); // ture


4.组合继承(伪经典继承)

结合了原型链继承和借用构造函数的技术。通过借用构造函数实现对实例属性的继承,通过原型链实现对原型属性和方法的继承(new父类的实例时不需要参数)。

缺点

调用了两次父类的构造函数,一次是new父类实例的时候,一次在子类构造函数call

function Point(x, y) {
  this.x = x;
  this.y = y;
  this.arr = [x, y];
}
Point.prototype.print = function () {
  console.log(`Point:(${this.x},${this.y})`);
};

function ColorPoint(x, y, color) {
  // 第二次调用父类构造函数
  Point.call(this, x, y);
  this.color = color;
}
// 第一次调用父类构造函数
ColorPoint.prototype = new Point(); // 不需要参数
ColorPoint.prototype.constructor = ColorPoint;
ColorPoint.prototype.printColor = function () {
  console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};

const cp = new ColorPoint(1, 2, "red");
cp.print(); // Point:(1,2)
cp.printColor(); // ColorPoint:(1,2) red [1,2]

console.log(cp instanceof Point); // true
console.log(cp instanceof ColorPoint); // ture


5.原型式继承

类似原型链继承,让子类的prototype等于父类的实例来实现继承。不过这里没有父类,只有一个对象,这种情况适用于让一个对象和另一个对象保持类似。

ES5的Object.create也能做到这样的效果:创建一个新对象,使用现有的对象来提供新创建的对象的__proto__

缺点同原型链继承

所有子类的__proto__指向是那个对象,这会导致对这个实例引用类型的修改,作用于所有的子类上

const point = {
  x: 1,
  y: 2,
  arr: [1, 2],
  print: function () {
    console.log(`Point:(${this.x},${this.y}) ${this.arr}`);
  },
};

function ColorPoint(obj) {
  function f() {}
  f.prototype = obj;
  return new f();
}

const cp = ColorPoint(point);
cp.print(); // Point:(1,2) 1,2
cp.arr.push(10086);

const cp2 = Object.create(point);
cp2.print(); // Point:(1,2) 1,2,10086

console.log(cp instanceof ColorPoint); // false


6.寄生组合式继承

使用空函数代替父类构造函数去创建实例,解决了组合继承调用两次父类构造函数的问题

function inherit(father, child) {
  function f() {}
  f.prototype = father.prototype;
  const obj = new f();

  // 类似ColorPoint.prototype = new Point();
  // 但是因为f是空函数,所以不需要执行父类的构造函数
  child.prototype = obj;
  obj.constructor = child;
}

function Point(x, y) {
  this.x = x;
  this.y = y;
  this.arr = [x, y];
}
Point.prototype.print = function () {
  console.log(`Point:(${this.x},${this.y})`);
};

function ColorPoint(x, y, color) {
  Point.call(this, x, y);
  this.color = color;
}

// 继承
inherit(Point, ColorPoint);

// 要在继承完毕后才能加属性,因为继承改了prototype
ColorPoint.prototype.printColor = function () {
  console.log(`ColorPoint:(${this.x},${this.y}) ${this.color} [${this.arr}]`);
};

const cp = new ColorPoint(1, 2, "red");
cp.print(); // Point:(1,2)
cp.printColor(); // ColorPoint:(1,2) red [1,2]

console.log(cp instanceof Point); // true
console.log(cp instanceof ColorPoint); // ture

?代码库

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-11 23:54:12  更:2022-01-11 23:56:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:31:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码