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
相关推荐
编程牛马姐18 小时前
独立站SEO流量增长:提高Google排名的优化方法
前端·javascript·网络
妮妮喔妮21 小时前
supabase的webhook报错
开发语言·前端·javascript
qq_120840937121 小时前
Three.js 大场景分块加载实战:从全量渲染到可视集调度
开发语言·javascript·数码相机
漂流瓶jz1 天前
运行时vs编译时:CSS in JS四种主流方案介绍和对比
前端·javascript·css
钮钴禄·爱因斯晨1 天前
他到底喜欢我吗?赛博塔罗Java+前端实现,一键解答!
java·开发语言·前端·javascript·css·html
Watermelo6171 天前
理解 JavaScript 中的“ / ”:路径、资源与目录、nginx配置、请求、转义的那些事
前端·javascript·vue.js·chrome·nginx·正则表达式·seo
Hello--_--World1 天前
JS:this指向、bind、call、apply、知识点与相关面试题
开发语言·javascript·ecmascript
jserTang1 天前
手撕 Claude Code-4: TodoWrite 与任务系统
前端·javascript·后端
腹黑天蝎座1 天前
大屏开发必读:Scale/VW/Rem/流式/断点/混合方案全解析(附完整demo)
前端·javascript
jserTang1 天前
手撕 Claude Code-5:Subagent 与 Agent Teams
前端·javascript·后端