当前位置: 首页 > article >正文

深入探究 JavaScript 中的继承方式

深入探究 JavaScript 中的继承方式

引言

在 JavaScript 的世界里,继承是构建复杂应用程序的重要基石。它允许我们在已有代码的基础上进行扩展和复用,从而提高开发效率。今天,就让我们一同深入探讨 JavaScript 中多种继承方式的奥秘。

在 JavaScript 中,继承的方式多种多样,每种方式都有其独特的优势和适用场景。我们先来看一种常见的方式:原型传递。

function Game (name, type) {
    this.name = name;
    this.type = type;
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}

// 现在有一个对象 LOL
function LOL() {}
// 他需要继承 Game 的属性和方法
// 原型传递
LOL.prototype = new Game('LOL', 'MOBA');
LOL.prototype.constructor = LOL;
const lol = new LOL();
lol.play(); // LOL MOBA 游戏正在玩

这种方式简单直接,通过将父类的实例赋给子类的原型,实现了属性和方法的继承。但它也存在一些问题。

重写原型法存在的问题

父类属性一旦赋值给子类的原型属性,此时就属于子类的共享属性,会导致继承者之间实例的篡改。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}

// 现在有一个对象 LOL
function LOL() {}
// 他需要继承 Game 的属性和方法
// 原型传递
LOL.prototype = new Game('LOL', 'MOBA');
LOL.prototype.constructor = LOL;
const lol = new LOL();
const lol2 = new LOL();
lol.play(); // LOL MOBA 游戏正在玩
lol2.play(); // LOL MOBA 游戏正在玩
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(lol2.skin); // ['史诗', '至臻']

而且在实例化时无法向父类传递参数,即无法创造一个不同的 LOL。

为了解决这些问题,我们引出了构造函数继承(经典继承)。

构造函数继承(经典继承)

通过在子类的构造函数中调用父类的构造函数,解决了实例的独立性。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}
// 现在有一个对象 LOL
function LOL(name, type) {
    Game.call(this, name, type);
}
const lol = new LOL('LOL', 'MOBA');
const wzry = new LOL('wzry', 'MOBA');
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(wzry.skin); // ['史诗']
// 构造函数继承解决了实例的独立性

lol.play(); // lol.play is not a function
wzry.play(); // wzry.play is not a function

然而,这种方式又带来了新的问题,即继承了父类的属性和方法,但没有原型传递,无法使用原型共享。

接着,我们来看原型链继承(组合继承)。

原型链继承(组合继承)

结合了原型传递和构造函数继承的优点。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}
// 现在有一个对象 LOL
function LOL(name, type) {
    // 第一次执行
    Game.call(this, name, type);
}
// 第二次执行
LOL.prototype = new Game();
const lol = new LOL('LOL', 'MOBA');
const wzry = new LOL('wzry', 'MOBA');
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(wzry.skin); // ['史诗']
// 构造函数继承解决了实例的独立性

lol.play(); // LOL MOBA 游戏正在玩
wzry.play(); // wzry MOBA 游戏正在玩

但它又存在一个问题,父类的构造函数会被执行两边。

最后,我们介绍寄生组合继承来解决这个问题。

寄生组合继承

通过使用 Object.create() 方法,避免了父类构造函数的重复执行。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}
// 现在有一个对象 LOL
function LOL(name, type) {
    Game.call(this, name, type);
}
LOL.prototype = Object.create(Game.prototype);
const lol = new LOL('LOL', 'MOBA');
const wzry = new LOL('wzry', 'MOBA');
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(wzry.skin); // ['史诗']
// 构造函数继承解决了实例的独立性

lol.play(); // LOL MOBA 游戏正在玩
wzry.play(); // wzry MOBA 游戏正在玩

结尾

通过对 JavaScript 中各种继承方式的深入探讨和代码示例,我们可以看到每种方式都有其独特的优势和适用场景。在实际开发中,我们需要根据具体需求选择合适的继承方式,以构建高效、可维护的 JavaScript 应用程序。希望本文能为你在 JavaScript 继承的探索之路上提供有益的参考。


http://www.kler.cn/a/394861.html

相关文章:

  • 企业一站式管理系统odoo的研究——PLM插件的搭建
  • 探索 HTML 和 CSS 实现的蜡烛火焰
  • [CKS] K8S Dockerfile和yaml文件安全检测
  • CSP/信奥赛C++语法基础刷题训练(8):洛谷P5718:找最小值
  • Python 中.title()函数和.lower()函数
  • 数字IC后端实现之Innovus specifyCellEdgeSpacing和ICC2 set_placement_spacing_rule的应用
  • WSL2安装Ubuntu22.04并开启GPU进行ML学习教程
  • Java NIO 深度解析:构建高效的 I/O 操作
  • WEB3.0介绍
  • 让Git走代理
  • 服务器数据恢复——Ext4文件系统使用fsck后mount不上的数据恢复案例
  • 【网络安全渗透测试零基础入门】之Vulnhub靶场PWNOS: 2.0 多种渗透方法,收藏这一篇就够了!
  • Rust 所有权机制
  • MacBook 下载vscode不能被解压及打开的解决方案
  • Oracle19C AWR报告分析之Instance Efficiency Percentages (Target 100%)
  • A tour of Go - Web Crawler
  • tomcat配合geoserver安装及使用
  • 【Elasticsearch】Elasticsearch集成Spring Boot
  • 7天用Go从零实现分布式缓存GeeCache(学习)(5)
  • 巧妙注入的奥秘:在 Spring 中优雅地使用 List 和 Map
  • 【SpringBoot】20 同步调用、异步调用、异步回调
  • 【学习】【HTML】块级元素,行内元素,行内块级元素
  • macos 搭建自己的git pages
  • awk是一种在 Linux 和 Unix 系统中非常强大且常用的文本处理工具
  • Linux( 权限+特殊权限 图片+大白话)
  • macOS系统下使用SQLark连接达梦数据库