2026/5/18 1:25:38
网站建设
项目流程
网站建设先进个人代表发言,数字媒体艺术设计主要学什么,房地产市场信息管理平台,仓库改造类网站怎么做如何声明一个类#xff1f;类如何继承#xff1f;—— JavaScript 类与继承完全指南
一、开篇#xff1a;类 ——JavaScript 面向对象编程的核心载体
在 JavaScript 的发展历程中#xff0c;从早期的构造函数 原型链实现面向对象#xff0c;到 ES6 引入class关键字提供…如何声明一个类类如何继承—— JavaScript 类与继承完全指南一、开篇类 ——JavaScript 面向对象编程的核心载体在 JavaScript 的发展历程中从早期的构造函数 原型链实现面向对象到 ES6 引入class关键字提供更规范、更贴近传统面向对象语言的类语法类已经成为构建可复用、可维护、层次化代码的核心载体。无论是 React/Vue 中的组件开发、Node.js 中的模块封装还是复杂业务逻辑的抽象都离不开类的声明与继承。很多初学者容易混淆 “类的声明方式”“原型方法与实例方法的区别”也会在继承中遇到 “构造函数调用”“方法重写”“超类访问” 等问题导致写出的代码层次混乱、难以扩展。本文将从类的声明基础到进阶、类的继承核心方法与细节、继承的实战场景与避坑指南三个维度结合完整示例深度拆解 JavaScript 类与继承的精髓帮你彻底掌握类的声明技巧与继承逻辑写出符合现代前端开发规范的面向对象代码。二、第一部分如何声明一个类从基础到进阶ES6 提供的class语法是声明类的标准方式本质是构造函数 原型链的语法糖但更简洁、更具可读性同时也保留了传统的 “构造函数 原型” 声明方式我们重点讲解现代开发中主流的class声明法同时补充传统方式作为底层理解参考。1. 基础声明使用class关键字核心方式1核心语法使用class关键字声明类类名遵循首字母大写的约定俗成区分普通函数提升代码可读性核心包含constructor构造函数和类方法原型方法。javascript运行// 基础类声明语法 class ClassName { // 1. 构造函数初始化实例属性可选若省略会默认生成空构造函数 constructor(param1, param2) { // 实例属性通过this绑定每个实例拥有独立的属性副本 this.prop1 param1; this.prop2 param2; } // 2. 原型方法类的核心方法所有实例共享该方法挂载在原型上 method1() { // 方法逻辑中可通过this访问实例属性和其他方法 return 实例属性${this.prop1}${this.prop2}; } // 3. 多个原型方法用逗号分隔ES6语法中可省略逗号更简洁 method2() { console.log(这是类的另一个原型方法); } }2实战示例声明一个User类javascript运行// 声明一个User类 class User { // 构造函数初始化用户名和年龄 constructor(name, age) { this.name name; // 实例属性用户名 this.age age; // 实例属性年龄 } // 原型方法展示用户信息 showInfo() { console.log(你好我是${this.name}今年${this.age}岁); } // 原型方法修改用户年龄带逻辑校验 setAge(newAge) { if (typeof newAge number newAge 0 newAge 150) { this.age newAge; console.log(年龄修改成功当前年龄${this.age}岁); } else { console.log(输入年龄不合法请输入0-150之间的数字); } } } // 实例化类使用new关键字创建类的实例必须带new否则报错 const user1 new User(张三, 25); const user2 new User(李四, 28); // 调用实例的原型方法 user1.showInfo(); // 输出你好我是张三今年25岁 user1.setAge(26); // 输出年龄修改成功当前年龄26岁 user2.showInfo(); // 输出你好我是李四今年28岁 // 验证所有实例共享原型方法内存复用提升性能 console.log(user1.showInfo user2.showInfo); // 输出true3核心要点说明constructor构造函数用于初始化实例属性是类的 “入口”当使用new创建实例时会自动调用constructor可选省略若省略JS 引擎会默认生成一个空的constructor()constructor() {}内部通过this绑定的属性是实例属性每个实例拥有独立的副本互不干扰不能返回非对象类型的值若返回对象会覆盖new创建的实例不推荐。类方法原型方法类内部直接定义的方法如showInfo()是原型方法挂载在类的prototype属性上所有实例共享该方法无需为每个实例创建独立的方法副本节省内存方法内部的this指向调用该方法的实例若单独提取方法需注意this绑定问题。实例化类必须使用new关键字调用类否则会抛出TypeError类不能像普通函数一样直接调用实例化时传入的参数会直接传递给constructor构造函数。2. 进阶声明类的其他成员静态方法、私有成员、get/set 访问器除了基础的构造函数和原型方法现代 JavaScript 类还支持静态方法、私有成员、get/set访问器等高级特性进一步丰富类的功能。1静态方法使用static关键字类本身的方法静态方法是挂载在类本身的方法不能被实例调用只能通过类名调用常用于定义工具方法、创建实例的工厂方法。javascript运行class User { constructor(name, age) { this.name name; this.age age; } showInfo() { console.log(你好我是${this.name}今年${this.age}岁); } // 静态方法用static关键字声明 static createAdmin() { // 静态方法内部可返回类的实例工厂方法 return new User(系统管理员, 0); } // 静态工具方法格式化用户信息 static formatUser(user) { return [用户信息] 姓名${user.name}年龄${user.age}; } } // 1. 调用静态方法创建实例不能通过实例调用 const admin User.createAdmin(); admin.showInfo(); // 输出你好我是系统管理员今年0岁 // 2. 调用静态工具方法 const formatStr User.formatUser(admin); console.log(formatStr); // 输出[用户信息] 姓名系统管理员年龄0 // 3. 实例调用静态方法报错静态方法不属于实例 console.log(admin.createAdmin); // 输出undefined // admin.createAdmin(); // 抛出TypeError: admin.createAdmin is not a function2私有成员#前缀ES2022受保护的成员私有成员私有属性、私有方法仅能在类内部访问外部和子类都无法直接访问用于保护类的内部状态避免外部意外篡改。javascript运行class User { // 私有属性用#前缀声明必须在类内部提前声明 #password; // 私有属性用户密码 constructor(name, age, password) { this.name name; this.age age; this.#password password; // 初始化私有属性 } showInfo() { console.log(你好我是${this.name}今年${this.age}岁); } // 私有方法用#前缀声明仅类内部可调用 #checkPassword(pwd) { return this.#password pwd; } // 公共方法间接访问私有成员对外暴露规范接口 verifyPassword(inputPwd) { const isCorrect this.#checkPassword(inputPwd); console.log(isCorrect ? 密码验证通过 : 密码验证失败); return isCorrect; } } const user new User(张三, 25, 123456); // 1. 调用公共方法间接访问私有成员 user.verifyPassword(123456); // 输出密码验证通过 user.verifyPassword(654321); // 输出密码验证失败 // 2. 外部直接访问私有成员报错私有成员对外隐藏 console.log(user.#password); // 抛出SyntaxError: Private field #password must be declared in an enclosing class // user.#checkPassword(123456); // 抛出SyntaxError: Private field #checkPassword must be declared in an enclosing class3get/set访问器优雅操作实例属性get和set访问器用于定义实例属性的 “读取” 和 “修改” 逻辑允许我们在访问 / 修改属性时添加额外处理如校验、格式化让属性操作更优雅、更安全。javascript运行class User { constructor(name, age) { this.name name; this._age age; // 约定下划线前缀表示“受保护属性”仅规范非语法层面私有 } // get访问器读取age属性时触发 get age() { console.log(正在读取年龄属性); return this._age; } // set访问器修改age属性时触发 set age(newAge) { console.log(正在修改年龄属性); if (typeof newAge number newAge 0 newAge 150) { this._age newAge; } else { console.log(输入年龄不合法无法修改); } } } const user new User(张三, 25); // 1. 读取age属性触发get访问器 console.log(user.age); // 输出正在读取年龄属性 → 25 // 2. 修改age属性触发set访问器 user.age 26; // 输出正在修改年龄属性 console.log(user.age); // 输出正在读取年龄属性 → 26 // 3. 传入不合法年龄触发set访问器的校验逻辑 user.age -10; // 输出正在修改年龄属性 → 输入年龄不合法无法修改3. 补充传统声明方式构造函数 原型链在 ES6 之前没有class关键字开发者通过 “构造函数 原型链” 实现类的功能这是class语法的底层实现理解该方式有助于深入掌握类的本质。javascript运行// 1. 构造函数对应class的constructor function User(name, age) { this.name name; this.age age; } // 2. 原型方法对应class的原型方法所有实例共享 User.prototype.showInfo function() { console.log(你好我是${this.name}今年${this.age}岁); }; User.prototype.setAge function(newAge) { if (typeof newAge number newAge 0 newAge 150) { this.age newAge; } }; // 3. 实例化与class一致使用new关键字 const user new User(张三, 25); user.showInfo(); // 输出你好我是张三今年25岁 // 验证class本质是构造函数的语法糖 console.log(typeof User); // 输出function console.log(User.prototype user.__proto__); // 输出true三、第二部分类如何继承核心方法与细节继承是面向对象编程的三大特性之一用于实现代码复用和层次化抽象—— 子类派生类可以继承父类超类、基类的属性和方法同时可以扩展自己的专属功能或重写父类的方法。JavaScript 中类的继承核心是使用extends关键字实现类的继承和super关键字访问父类成员这是现代开发的标准方式。1. 基础继承使用extends关键字实现父类属性与方法的继承1核心语法javascript运行// 父类超类、基类 class ParentClass { constructor(param1) { this.parentProp param1; } parentMethod() { console.log(这是父类的原型方法); return this.parentProp; } } // 子类派生类使用extends关键字继承父类 class ChildClass extends ParentClass { constructor(param1, param2) { // 必须先调用super()初始化父类构造函数否则报错 super(param1); // 再初始化子类自己的实例属性 this.childProp param2; } // 子类自己的原型方法扩展功能 childMethod() { console.log(这是子类的原型方法); return this.childProp; } }2实战示例AdminUser子类继承User父类javascript运行// 父类User类 class User { constructor(name, age) { this.name name; this.age age; } showInfo() { console.log(姓名${this.name}年龄${this.age}); } setAge(newAge) { if (typeof newAge number newAge 0 newAge 150) { this.age newAge; console.log(年龄修改为${this.age}岁); } else { console.log(年龄输入不合法); } } } // 子类AdminUser类继承User类 class AdminUser extends User { constructor(name, age, role) { // 1. 调用super()传入父类构造函数所需的参数初始化父类属性 super(name, age); // 2. 初始化子类专属属性 this.role role; // 子类专属属性管理员角色如超级管理员、普通管理员 } // 3. 子类专属方法扩展父类没有的功能 showRole() { console.log(角色${this.role}); } } // 实例化子类 const admin new AdminUser(系统管理员, 0, 超级管理员); // 1. 调用继承自父类的方法 admin.showInfo(); // 输出姓名系统管理员年龄0 admin.setAge(1); // 输出年龄修改为1岁 // 2. 调用子类自己的专属方法 admin.showRole(); // 输出角色超级管理员 // 3. 验证子类实例同时拥有父类和子类的属性 console.log(admin.name, admin.age, admin.role); // 输出系统管理员 1 超级管理员3核心要点说明extends关键字用于声明子类继承父类子类会自动继承父类的所有公共实例属性和原型方法私有成员无法继承支持链式继承如GrandChild extends Child extends Parent但不推荐过深的继承链增加代码复杂度。super关键字的核心作用必须掌握在子类构造函数中必须先调用super()才能使用this关键字否则会抛出ReferenceErrorsuper()本质是调用父类的构造函数需传入父类构造函数所需的参数若子类省略constructorJS 引擎会默认生成一个构造函数自动调用super()并传递所有参数constructor(...args) { super(...args); }。2. 进阶继承方法重写与super访问父类方法子类不仅可以继承父类的方法还可以重写覆盖父类的方法实现子类专属的逻辑同时可以通过super.方法名()在重写的方法中访问父类的原方法实现 “扩展父类方法” 而非 “完全覆盖”。1方法重写子类覆盖父类的方法javascript运行class User { constructor(name, age) { this.name name; this.age age; } showInfo() { console.log(【父类方法】姓名${this.name}年龄${this.age}); } } class AdminUser extends User { constructor(name, age, role) { super(name, age); this.role role; } // 方法重写子类覆盖父类的showInfo()方法 showInfo() { console.log(【子类方法】姓名${this.name}年龄${this.age}角色${this.role}); } } const admin new AdminUser(系统管理员, 0, 超级管理员); admin.showInfo(); // 输出【子类方法】姓名系统管理员年龄0角色超级管理员2扩展父类方法通过super访问父类原方法很多场景下我们不需要完全覆盖父类方法而是在父类方法的基础上扩展功能此时可以通过super.方法名()调用父类的原方法。javascript运行class User { constructor(name, age) { this.name name; this.age age; } showInfo() { console.log(姓名${this.name}年龄${this.age}); } } class AdminUser extends User { constructor(name, age, role) { super(name, age); this.role role; } // 扩展父类方法先调用父类原方法再添加子类专属逻辑 showInfo() { // 调用父类的showInfo()方法通过super访问 super.showInfo(); // 子类专属扩展逻辑 console.log(角色${this.role}); } } const admin new AdminUser(系统管理员, 0, 超级管理员); admin.showInfo(); // 输出结果 // 姓名系统管理员年龄0 // 角色超级管理员3. 特殊继承静态方法的继承与私有成员的继承规则1静态方法的继承子类会自动继承父类的静态方法可通过子类名.静态方法名()调用无需额外配置。javascript运行class User { constructor(name, age) { this.name name; this.age age; } // 父类静态方法 static formatUser(user) { return [用户] 姓名${user.name}年龄${user.age}; } } class AdminUser extends User { constructor(name, age, role) { super(name, age); this.role role; } } const admin new AdminUser(系统管理员, 0, 超级管理员); // 子类继承父类的静态方法通过子类名调用 const formatStr AdminUser.formatUser(admin); console.log(formatStr); // 输出[用户] 姓名系统管理员年龄02私有成员的继承规则父类的私有成员#前缀声明无法被子类继承子类既不能直接访问父类的私有成员也不能重写父类的私有方法私有成员仅在定义它的类内部可见。javascript运行class User { #password; // 父类私有属性 constructor(name, age, password) { this.name name; this.age age; this.#password password; } // 父类私有方法 #checkPassword(pwd) { return this.#password pwd; } // 父类公共方法间接访问私有成员 verifyPassword(pwd) { return this.#checkPassword(pwd); } } class AdminUser extends User { constructor(name, age, password, role) { super(name, age, password); this.role role; } // 子类尝试访问父类私有成员报错 showPassword() { // console.log(this.#password); // 抛出SyntaxError: Private field #password must be declared in an enclosing class } } const admin new AdminUser(系统管理员, 0, 123456, 超级管理员); // 子类可调用父类公共方法但无法直接访问父类私有成员 console.log(admin.verifyPassword(123456)); // 输出true四、第三部分继承的实战避坑指南1. 坑 1子类构造函数中未先调用super()使用this报错问题现象子类构造函数中在调用super()之前使用this会抛出ReferenceError: Must call super constructor in derived class before accessing this or returning from derived constructor。解决方案子类构造函数中必须先调用super()再初始化子类的实例属性使用thissuper()是初始化父类实例的关键只有父类实例初始化完成子类才能安全地使用this。javascript运行class AdminUser extends User { constructor(name, age, role) { // 错误先使用this后调用super() // this.role role; // 抛出错误 // 正确先调用super()再使用this super(name, age); this.role role; } }2. 坑 2重写父类方法时忽略super导致父类逻辑丢失问题现象子类重写父类方法时直接编写子类逻辑未调用super.方法名()导致父类方法中的核心逻辑丢失出现功能异常。解决方案若需要扩展父类方法而非完全覆盖务必在子类重写的方法中调用super.方法名()保留父类核心逻辑。3. 坑 3过深的继承链导致代码难以维护问题现象使用链式继承如A extends B extends C extends D继承链过深当需要修改某个类的逻辑时会影响所有子类且代码追踪困难。解决方案控制继承链深度尽量不超过 3 层优先使用 “组合” 而非 “继承” 实现功能复用如将公共逻辑封装为模块在类中引入使用遵循 “里氏替换原则”子类必须能够替换父类且不改变父类的核心行为。4. 坑 4混淆实例方法与静态方法的继承规则问题现象尝试通过子类实例调用父类的静态方法导致报错。解决方案明确静态方法的调用规则 ——静态方法属于类本身只能通过类名调用不能通过实例调用子类继承的静态方法也遵循该规则。五、总结类与继承的核心知识点回顾与实战准则类的声明核心现代开发优先使用class关键字核心包含constructor构造函数初始化实例属性和原型方法所有实例共享高级特性static静态方法类本身的方法、#私有成员类内部保护、get/set访问器优雅操作属性。类的继承核心基础继承使用extends关键字实现子类继承父类子类自动继承父类的公共实例属性和原型方法关键细节子类构造函数中必须先调用super()才能使用this进阶操作方法重写覆盖父类方法、super访问父类方法扩展父类功能。实战准则类名首字母大写方法命名语义化提升代码可读性优先使用组合而非继承实现功能复用控制继承链深度私有成员用于保护内部状态对外暴露规范的公共接口重写父类方法时按需保留父类逻辑通过super避免功能丢失。类与继承是 JavaScript 面向对象编程的核心掌握它们不仅能写出更具层次化、可复用的代码更能深入理解现代前端框架的底层设计思想如 React 的组件继承、Vue 的混入机制。最后用一句话总结类是抽象业务逻辑的载体继承是实现代码复用的桥梁合理声明类、优雅使用继承才能构建出健壮、可扩展的前端应用。