深入理解 JavaScript 原型与继承:从基础到进阶

个人空间: https://blog.csdn.net/m0_73589512https://blog.csdn.net/m0_73589512大家好,我是 叁佰万**~~**

如果本文对您有帮助,请献上你的小❥(^_-)哟~~~

接续上文:

https://blog.csdn.net/m0_73589512/article/details/157100846https://blog.csdn.net/m0_73589512/article/details/157100846

目录

[深入理解 JavaScript 原型与继承:从基础到进阶](#深入理解 JavaScript 原型与继承:从基础到进阶)

一、编程范式:面向过程、面向对象与函数式

[1. 面向过程编程](#1. 面向过程编程)

[2. 面向对象编程(OOP)](#2. 面向对象编程(OOP))

[3. 函数式编程](#3. 函数式编程)

[二、JS 的对象系统:简单对象、函数对象与原型](#二、JS 的对象系统:简单对象、函数对象与原型)

[1. 简单对象:最基础的数据容器](#1. 简单对象:最基础的数据容器)

[2. 函数对象:构造函数的核心载体](#2. 函数对象:构造函数的核心载体)

[3. 原型对象:继承的底层逻辑](#3. 原型对象:继承的底层逻辑)

[三、new 的底层:构造函数创建实例的过程](#三、new 的底层:构造函数创建实例的过程)

[四、JS 继承方式的演进:从 "有缺陷" 到 "最优解"](#四、JS 继承方式的演进:从 “有缺陷” 到 “最优解”)

[1. 构造函数继承:解决 "引用类型共享" 问题](#1. 构造函数继承:解决 “引用类型共享” 问题)

[2. 原型链继承:解决 "方法复用" 问题](#2. 原型链继承:解决 “方法复用” 问题)

[3. 组合继承:融合前两者的优点](#3. 组合继承:融合前两者的优点)

[4. 寄生组合继承:最优解](#4. 寄生组合继承:最优解)

[5. ES6 class:语法糖简化继承](#5. ES6 class:语法糖简化继承)

五、核心总结:原型与继承的关键认知


深入理解 JavaScript 原型与继承:从基础到进阶

在 JavaScript 的世界里,"面向对象" 始终是绕不开的核心话题,但与 Java、C++ 等传统面向对象语言不同,JS 并非基于 "类",而是靠构造函数 + 原型搭建起独特的对象系统。本文将从编程范式对比入手,拆解原型、原型链的本质,梳理 JS 继承方式的演进脉络,帮你彻底搞懂这一核心知识点。

一、编程范式:面向过程、面向对象与函数式

在聊 JS 的对象系统前,先明确编程范式的差异 ------ 这能帮我们理解 "为什么 JS 要这么设计"。

1. 面向过程编程

核心是 "以步骤为中心",按时间顺序拆解任务,数据与操作分离。比如实现 "用户下单",会拆成 "校验参数→查询库存→扣减库存→生成订单" 等步骤,步骤间依赖极强,容易产生冗余代码和复杂的调用链。

2. 面向对象编程(OOP)

核心是 "以对象为中心",将数据和操作封装成 "模板(类 / 构造函数)",通过实例化创建独立对象。它的核心特性是:

  • 封装:数据和方法包裹在对象内,隐藏内部细节;
  • 继承:子类复用父类的属性和方法;
  • 多态:同一方法在不同对象上有不同实现;
  • 抽象:只暴露必要接口,屏蔽复杂逻辑。

3. 函数式编程

核心是 "以函数为中心",强调纯函数、不可变性,避免共享状态和副作用,像 "管道" 一样串联函数处理数据。

JS 并非单一范式语言,而是支持多范式,但它的 OOP 体系最具特色 ------ 基于原型,而非类

二、JS 的对象系统:简单对象、函数对象与原型

JS 里 "万物皆对象",但对象也分类型,不同类型的对象承担着不同的角色。

1. 简单对象:最基础的数据容器

简单对象就是键值对的集合,没有类模板,直接定义,适合做数据载体:

复制代码
// 字面量创建
const person = {
  name: 'Alice',
  age: 21,
  greet: function() {
    return `hello,I'am ${this.name}`;
  }
};

// Object构造函数创建
const car = new Object();
car.brand = 'Toyota';

它的特点是:属性可以是原始值、对象或函数,但无法实例化、复用性低

2. 函数对象:构造函数的核心载体

在 JS 中,函数也是对象 ------ 这是理解构造函数的关键。函数对象不仅能执行逻辑,还拥有特殊属性:

复制代码
function Person(name) {
  this.name = name;
}
// 函数对象的特殊属性
console.log(Person.name); // "Person"(函数名)
console.log(Person.length); // 1(形参个数)
console.log(Person.prototype); // 原型对象(构造函数专属)

其中,prototype是核心 ------ 只有函数对象拥有这个属性,它是后续实现 "继承" 的基础。

3. 原型对象:继承的底层逻辑

每个实例对象都有__proto__属性(指向其原型),每个构造函数都有prototype属性(指向原型对象),这两者共同构成了 "原型链":

复制代码
function Animal(name) {
  this.name = name;
}
// 原型对象上定义共享方法
Animal.prototype.eat = function() {
  return `${this.name} is eating`;
};

const dog = new Animal('Dog');
// 原型链:dog -> Animal.prototype -> Object.prototype -> null
console.log(dog.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true

__proto__就像 "血缘关系",实例访问属性 / 方法时,会沿着原型链向上查找,直到null------ 这就是 JS 继承的本质。

三、new 的底层:构造函数创建实例的过程

new调用构造函数时,JS 会自动完成 4 步操作:

  1. 创建空对象:生成一个新的空对象作为实例;
  2. 绑定原型 :空对象的__proto__指向构造函数的prototype
  3. 绑定 this :将构造函数的this指向这个空对象;
  4. 执行构造函数:运行构造函数的初始化代码,给实例添加属性。

这一步的关键是:实例之间彼此独立,但能通过原型链共享方法,既保证了独立性,又实现了代码复用。

四、JS 继承方式的演进:从 "有缺陷" 到 "最优解"

继承的核心需求是 "复用父类的属性和方法",但早期 JS 没有class语法,开发者摸索出了多种继承方式,一步步从 "有缺陷" 走向 "最优解"。

1. 构造函数继承:解决 "引用类型共享" 问题

核心是通过Parent.call(this)调用父类构造函数,让子类实例拥有独立的属性:

复制代码
function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

function Child(name, age) {
  Parent.call(this, name); // 盗用父类构造函数
  this.age = age;
}

const child1 = new Child('Alice', 10);
child1.colors.push('green');
console.log(child2.colors); // ['red', 'blue'](实例属性独立)

优点 :实例属性不共享、可向父类传参;缺点:方法无法复用(每个实例都会创建新方法)、无法访问父类原型的方法。

2. 原型链继承:解决 "方法复用" 问题

核心是将子类原型指向父类实例,让子类能访问父类原型的方法:

复制代码
function Parent() {
  this.name = 'Parent';
}
Parent.prototype.sayName = function() {
  return this.name;
};

function Child(age) {
  this.age = age;
}
Child.prototype = new Parent(); // 绑定原型链
Child.prototype.constructor = Child; // 修复constructor指向

优点 :方法可复用;缺点:引用类型属性被所有实例共享、无法向父类传参。

3. 组合继承:融合前两者的优点

结合 "构造函数继承"(继承实例属性)和 "原型链继承"(继承原型方法):

复制代码
function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name); // 继承实例属性(第二次调用父类)
  this.age = age;
}
Child.prototype = new Parent(); // 继承原型方法(第一次调用父类)
Child.prototype.constructor = Child;

优点 :实例属性独立、方法可复用、可传参;缺点:父类构造函数被调用两次,子类原型存在冗余属性。

4. 寄生组合继承:最优解

核心是通过Object.create()创建父类原型的副本,替代 "子类原型 = 父类实例",避免父类构造函数被重复调用:

复制代码
// 封装继承逻辑
function inheritPrototype(child, parent) {
  const prototype = Object.create(parent.prototype); // 父类原型副本
  prototype.constructor = child; // 修复constructor
  child.prototype = prototype;
}

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name); // 仅调用一次父类
  this.age = age;
}
inheritPrototype(Child, Parent); // 绑定原型链

这是 JS 继承的 "最终方案"------ES6 的class extends底层就是基于这种方式实现的。

5. ES6 class:语法糖简化继承

ES6 的**class本质** 是构造函数的语法糖,让继承更直观:

复制代码
class Parent {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    return this.name;
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name); // 相当于Parent.call(this, name)
    this.age = age;
  }
  sayAge() {
    return this.age;
  }
}

写法更接近传统面向对象语言,但底层逻辑依然是 "原型 + 构造函数"。

五、核心总结:原型与继承的关键认知

  1. prototype vs proto

    • prototype是构造函数的属性,用于 "定义 / 设计" 继承关系(蓝图);
    • __proto__是实例的属性,用于 "实现 / 查找" 继承关系(血缘);
    • 业务代码中优先用Object.getPrototypeOf()/Object.setPrototypeOf(),避免直接操作__proto__
  2. 继承方式选择

    • 简单需求:用 ES6 class(底层是寄生组合继承);
    • 多继承需求:用 "混入(Mixin)" 实现;
    • 避免过度设计:组合优于继承,优先用对象组合替代复杂继承链。
  3. 本质:JS 的面向对象核心是 "原型复用",所有继承方式的最终目的都是 ------ 在保证实例独立的前提下,最大化代码复用。

理解原型和继承,不仅能写出更优雅的 JS 代码,更能看懂框架源码中的设计思路(比如 Vue 的原型链、React 的类组件)。从构造函数到原型链,从组合继承到寄生组合继承,每一步演进都是为了弥补前一种方式的缺陷 ------ 这也是编程的核心:发现问题,解决问题,优化方案。

相关推荐
博客zhu虎康2 小时前
音频视频处理:前端直播流播放 flv
前端
晨非辰2 小时前
C++波澜壮阔40年|类和对象篇:拷贝构造与赋值重载的演进与实现
运维·开发语言·c++·人工智能·后端·python·深度学习
m0_719084112 小时前
滴滴滴滴滴
java·开发语言
董世昌412 小时前
深度解析var、let、const的区别与最佳使用场景
开发语言·前端·javascript
FJW0208142 小时前
Python中的闭包
开发语言·python
C_心欲无痕2 小时前
Next.js 平行路由:构建模块化动态布局
开发语言·前端·javascript
warrah2 小时前
前端项目容器化部署问题
前端·docker
GISer_Jing2 小时前
2026前端技术潜在主流前沿方向
前端·人工智能·reactjs
切糕师学AI2 小时前
Vue 中的生命周期钩子
前端·javascript·vue.js