0

0

JavaScript 类继承中 super 调用方法未找到的排查与解决

心靈之曲

心靈之曲

发布时间:2025-07-08 18:36:22

|

971人浏览过

|

来源于php中文网

原创

JavaScript 类继承中 super 调用方法未找到的排查与解决

本文探讨在 JavaScript 类继承中,子类通过 super 调用父类方法时遇到 TypeError 的常见原因及解决方案。当父类方法被定义为构造函数内部的实例属性而非原型方法时,super 机制无法正确查找。文章将详细阐述这一机制差异,并提供将方法定义为类体内部的原型方法,以及利用 ES2022 私有字段管理内部状态的正确实践,确保继承链中方法调用的顺畅与代码的健壮性。

JavaScript 类继承与 super 关键字

在 javascript 中,类继承允许我们构建基于现有类的子类,从而实现代码复用和层次结构。super 关键字在子类中扮演着核心角色,它允许我们调用父类的构造函数(super())或访问父类的方法和属性(super.method())。然而,在使用 super 调用父类方法时,一个常见的陷阱可能导致 typeerror,即父类方法未被正确识别。

问题根源:构造函数内部定义的方法与原型方法

当我们在父类构造函数内部使用 this.methodName = () => {} 的形式定义方法时,实际上是为每个实例创建了一个独立的 methodName 属性,这个属性的值是一个函数。这种方法被称为“实例方法属性”或“绑定方法”,因为它直接绑定到实例上。

class Parent {
  constructor() {
    // 实例方法属性:每个实例都有自己的 updateUI 函数
    this.updateUI = (arg1, arg2) => {
      console.log('Parent updateUI called');
    };
  }
}

class Child extends Parent {
  constructor() {
    super();
  }

  doSomething() {
    // 尝试调用 super.updateUI()
    // 问题在于 super 查找的是原型链上的方法,而不是实例属性
    super.updateUI(); // 会抛出 TypeError
  }
}

const childInstance = new Child();
childInstance.doSomething(); // Uncaught TypeError: (intermediate value).updateUI is not a function

super.method() 的机制是,它会在当前实例的原型链上查找 method。如果 method 是在类体内部直接定义的方法(即原型方法),它就会被正确找到。但如果 method 是在构造函数内部作为实例属性定义的,那么它就不在原型链上,super 自然无法找到,从而导致 TypeError。

解决方案:将方法定义为原型方法

解决此问题的最直接和推荐的方法是将方法定义在类体内部,而不是构造函数内部。这样定义的方法会自动添加到类的原型上,成为原型方法,所有实例共享同一个方法定义,并且 super 机制可以正确地在原型链上找到它们。

// 父类:RosterTableUtil
class RosterTableUtil {
  // 定义内部状态,可以使用私有字段(ES2022)增强封装性
  #highLightCellIndex = -1;
  #highLightRowIndex = -1;

  // 将 updateUI 定义为原型方法
  updateUI(cellIndex, rowIndex) {
    this.#highLightCellIndex = cellIndex;
    this.#highLightRowIndex = rowIndex;
    console.log(`RosterTableUtil: Highlighting row ${this.#highLightRowIndex}, cell ${this.#highLightCellIndex}`);
  }
}

// 子类:RosterSchedulerTableUtil
class RosterSchedulerTableUtil extends RosterTableUtil {
  constructor() {
    super(); // 调用父类构造函数
    // 其他初始化逻辑...
  }

  // 重写 updateUI 方法
  updateUI(cellIndex, rowIndex) {
    // 正确调用父类的 updateUI 方法
    super.updateUI(cellIndex, rowIndex);

    // 子类特有的逻辑
    this.#updateSelectRegion(cellIndex, rowIndex); // 假设有私有辅助方法
    console.log(`RosterSchedulerTableUtil: Also updating select region.`);
  }

  // 子类内部辅助方法(示例)
  #updateSelectRegion(cellIndex, rowIndex) {
    // 实现选择区域更新逻辑
  }
}

// 示例使用
const schedulerUtil = new RosterSchedulerTableUtil();
schedulerUtil.updateUI(1, 2); // 正常调用,不再报错
schedulerUtil.updateUI(3, 4);

在上述代码中:

立即学习Java免费学习笔记(深入)”;

微信 WeLM
微信 WeLM

WeLM不是一个直接的对话机器人,而是一个补全用户输入信息的生成模型。

下载
  1. RosterTableUtil 类中的 updateUI 方法直接定义在类体内部,使其成为原型方法。
  2. 内部状态 highLightCellIndex 和 highLightRowIndex 使用了 ES2022 引入的私有字段(# 前缀)进行封装。私有字段只能在类的内部访问,提供了更强的封装性,是替代构造函数内部闭包变量的现代方式。
  3. RosterSchedulerTableUtil 子类中的 updateUI 方法通过 super.updateUI(cellIndex, rowIndex) 成功调用了父类的原型方法。

注意事项与最佳实践

  • 原型方法 vs. 实例方法属性:

    • 原型方法(推荐): 定义在类体内部。它们存在于类的原型上,所有实例共享同一个方法引用,节省内存。super 关键字可以正确访问它们。
    • 实例方法属性: 定义在构造函数内部,或使用类字段语法直接在类体中作为箭头函数定义。每个实例都有一个独立的方法副本。如果方法需要绑定 this 到实例(例如作为事件处理器),并且不涉及 super 调用,这可能是一个选择,但通常可以通过在构造函数中绑定或在调用时使用箭头函数来避免。
  • 封装内部状态:

    • 如果需要管理类的内部状态,并且不希望外部直接访问,ES2022 的私有字段 (#fieldName) 是最佳选择。它们提供了真正的私有性。
    • 避免在构造函数内部使用闭包来“私有化”变量,因为这可能导致代码结构复杂,并且如本例所示,与继承机制不兼容。
  • 代码可读性与维护性: 将方法定义为原型方法,使类结构更清晰,更符合面向对象编程的习惯。这也有助于优化内存使用,因为所有实例共享相同的方法定义,而不是为每个实例创建单独的函数副本。

总结

在 JavaScript 类继承中,理解 super 关键字查找方法的机制至关重要。当子类通过 super 调用父类方法时,该方法必须是定义在父类原型上的“原型方法”,而不是在构造函数内部作为实例属性创建的函数。通过将方法直接定义在类体内部,并结合使用现代 JavaScript 特性如私有字段来管理内部状态,我们可以构建出更健壮、更易于维护的面向对象代码。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

559

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

437

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

776

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

479

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

554

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

1091

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

659

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

554

2023.09.20

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

31

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 3.5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号