JavaScript对象继承常用详解

JavaScript对象继承常用详解

一、概念: JS继承是让** 一个对象共享另一个对象的属性和方法的核心机制,JS是基于原型(proptotype)的继承,和传统类继承不同。**

原型链核心,JS每个对象都有一个__propto 属性,指向它的原型对象,函数有proptotype属性,实例对象的 propto __指向构造函数的proptotype, 继承的本质是让子类的原型指向父类的实例/原型

5种常见的继承方式

1、原型链继承(基础)

核心: 子类原型=父类实例

javascript 复制代码
// 父类
function Parent() {
    this.name = '父类';
    this.arr=[1,2,3]; // 引用类型属性
}
Parent.prototype.say = function () {
    console.log('我是来自父类的name ' + this.name);
}

// 子类 
function  Child() {}
// 核心:子类原型继承父类实例
Child.prototype = new Parent();

const child1 = new Child();
const child2 = new Child();
child1.say(); // 我是父类 父类

child1.arr.push(4);
console.log(child1.arr);   // [1, 2, 3, 4]
console.log(child2.arr);   // [1, 2, 3, 4]   // 子类实例共享父类实例的引用类型属性

缺点:

  • 引用类型属性(数组/对象)会被所有子类实例共享,修改一个实例,所有实例都会变化,如修改child1.arr,push一个值4,child2.arr也会变更,
  • 无法向父类构造函数传值

2、借用构造函数继承,解决第1方法的缺点

核心:在子类构造函数中,用call() 调用父类构造函数

javascript 复制代码
function Parent(name) {
    this.name = name;
    this.arr = [1, 2, 3];
}

Parent.prototype.say = function () {    
    console.log('我是来自父类的方法 say');
}

function Child(name) {
    Parent.call(this, name); // 通过 call 方法调用父类构造函数,传递子类实例作为 this
    this.age = 18; // 子类特有属性
}
const child1 = new Child('子类1');
const child2 = new Child('子类2');
// 独立修改,不影响其他实例
child1.arr.push(4);
console.log(child1.arr); // [1, 2, 3, 4]  // 子类实例共享父类实例的引用类型属性,
console.log(child2.arr); // [1, 2, 3]  // 子类实例共享父类实例的引用类型属性,
console.log(child1.name,child2.name); // 子类1 子类2

console.log(child1.say); // undefined  // 子类实例无法访问父类原型上的方法
console.log(child2.say); // undefined  // 子类实例无法访问父类原型上的方法

缺点:

  • 只能继承父类实例属性,无法继承父类原型上的方法
  • 方法会重复创建,浪费内存

3、组合继承(最常用经典方案)

核心:原型链继承+借用构造函数继承,取长补短, 解决第2中方法的缺点

javascript 复制代码
function Parent(name) {
    this.name = name;
    this.arr = [1, 2, 3];
}

Parent.prototype.say = function () {
    console.log('我是来自父类的方法 say ' + this.name);
}

function Child(name, age) {
    //1. 借用构造函数:继承实例属性+传参
    Parent.call(this, name); 
    this.age = age; // 子类特有属性
}
//2. 原型链继承:继承原型方法
Child.prototype = new Parent(); 
Child.prototype.constructor = Child; // 修正子类原型的 constructor 属性
const child1 = new Child('子类1', 18);
const child2 = new Child('子类2', 20);
child1.say(); //
console.log(child1.name, child1.age); // 子类1 18
child1.arr.push(4);
console.log(child1.arr); // [1, 2, 3, 4]  // 子类实例共享父类实例的引用类型属性,    

console.log(child2.arr); // [1, 2, 3]  // 子类实例共享父类实例的引用类型属性,独立属性,child1修改不影响child2

优点:

  • 支持传参
  • 引用类型(对象/数据)属性不共享
  • 方法复用,不浪费内存

缺点:

  • 父类构造函数会执行两次,new Parent()一次, call() 一次

4、寄生组合式继承(JS最佳实践)

核心:解决组合式继承父类构造函数执行两次的问题

javascript 复制代码
function Parent(name) {
    this.name = name;
    this.arr = [1, 2, 3];
}
Parent.prototype.say = function () {
    console.log('我是来自父类的方法 say ' + this.name);
}
function Child(name, age) {
    Parent.call(this, name); // 仅执行一次父类构造函数,传递子类实例作为 this
    this.age = age; 
}   
// 核心:创造父类原型的副本,不执行父类构造函数
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;    
const child1 = new Child('子类1', 18);;
child1.say(); // 我是来自父类的方法 say 子类1
console.log(child1.name, child1.age);// 子类1 18

优点:

  • 父类构造函数只执行一次
  • 完美支持传参、方法复用、属性独立
  • ES6 class继承的底层实现原

5、ES6 class继承

核心:extends + super() ,语法简洁,底层还是寄生组合式继承

javascript 复制代码
// 父类
class Parent {
    constructor(name) {
        this.name = name;
        this.arr = [1, 2, 3];
    }
    say() {
        console.log('我是来自父类的方法 say ' + this.name);
    }   
}   

// 子类继承父类
class child extends Parent { 
    constructor(name, age) {
        super(name);    // 调用父类构造函数,传递 name 参数,必须在this之前调用super()
        this.age = age; // 子类特有属性
    }
}
const child1 = new child('子类1', 18);
child1.say(); // 我是来自父类的方法 say 子类1
console.log(child1.name, child1.age); // 子类1 18
相关推荐
花归去21 分钟前
vue3中 function getText(){} 、 const getText=()=>{} ;区别在哪里,优缺点
javascript·vue.js·ecmascript
ZC跨境爬虫34 分钟前
跟着 MDN 学 HTML day_33:(Attr 接口与属性节点的深入理解)
前端·javascript·ui·html·音视频·html5
红色的小鳄鱼1 小时前
前端面试js手写
开发语言·前端·javascript
web行路人1 小时前
前端对Commands(斜杠命令)一些常用
前端·javascript·vue.js·vue
竹林8181 小时前
用 ethers.js 连 MetaMask 做钱包登录,我踩了三个坑才搞定跨页面状态同步
前端·javascript
阿星做前端1 小时前
重度 AI 编程用户的一天:我怎么把 Claude Code / Codex 工作流搬进浏览器工作台
前端·javascript·后端
风止何安啊1 小时前
手写 URL 解析器,面试官到底想考什么?
前端·javascript·面试
TEC_INO2 小时前
Linux50:ROCKX+RV1126视频流检测人脸
开发语言·前端·javascript
下载居2 小时前
Node.js(Javascript运行环境) 26.1
开发语言·javascript·node.js
ZC跨境爬虫4 小时前
跟着 MDN 学 HTML day_32:(AbstractRange 抽象接口与 DOM 范围操作)
前端·javascript·ui·html·音视频