news 2026/4/23 17:32:32

JavaScript面向对象编程的演变

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript面向对象编程的演变

JavaScript 是产生“类”的?又是如何演变成“面向对象”的?Class语法糖背后隐藏着什么秘密?本篇文章将完整梳理 JavaScript 面向对象编程的发展历程。

前言:为什么JavaScript需要面向对象?

var name = '张三'; var age = 25; var job = '工程师'; function sayHello(person) { console.log('你好,我是' + person.name); }

在早期的 JavaScript 代码中,我们通常采用的是过程式编程。但随着应用复杂度增加,我们需要更好的代码组织方式,因此面向对象编程应运而生。
工厂模式:面向对象的雏形
什么是工厂模式?
工厂模式是最简单的创建对象的方式,它就像一个“工厂”一样批量生产对象。我们来看一个简单的工厂模式示例:

// 创建Person对象的工厂 function createPerson(name, age, job) { // 1. 创建一个新对象 var obj = {}; // 2. 添加属性 obj.name = name; obj.age = age; obj.job = job; // 3. 添加方法 obj.sayHello = function() { console.log('你好,我是' + this.name + ',今年' + this.age + '岁'); }; obj.work = function() { console.log(this.name + '正在工作:' + this.job); }; // 4. 返回对象 return obj; } // 使用工厂模式创建对象 var person1 = createPerson('张三', 25, '前端工程师'); var person2 = createPerson('李四', 30, '后端工程师'); person1.sayHello(); // 你好,我是张三,今年25岁 person2.work(); // 李四正在工作:后端工程师 console.log(person1.sayHello === person2.sayHello); // false

但这种方式存在一个问题:每个对象都有独立的方法副本,浪费内存。
工厂模式的优点

  1. 简单易懂
  2. 可以创建多个相似对象
  3. 封装了创建过程

工厂模式的缺点

  1. 无法识别对象类型:person1 instanceof createPerson; // false
  2. 方法重复创建,内存浪费

构造函数模式:引入"类型"概念
什么是构造函数?
构造函数通过new关键字创建对象,解决了工厂模式的类型识别问题。我们来看一个简单的示例:

// 构造函数模式 function Person(name, age, job) { // 1. 创建一个新对象(隐式:this = {}) // 2. 设置原型链(隐式:this.__proto__ = Person.prototype) // 3. 添加属性 this.name = name; this.age = age; this.job = job; // 4. 添加方法(仍然有问题) this.sayHello = function() { console.log('你好,我是' + this.name); }; // 5. 返回this(隐式:return this) } // 使用new关键字创建对象(实例) var person1 = new Person('张三', 25, '工程师'); var person2 = new Person('李四', 30, '设计师'); person1.sayHello(); // 你好,我是张三 person2.sayHello(); // 你好,我是李四 console.log(person1 instanceof Person); // true console.log(person1 instanceof Object); // true console.log(person1.constructor === Person); // true console.log(person1.sayHello === person2.sayHello); // false

从上述代码中,我们可以看出:构造函数模式中,可以识别对象类型了;但每个实例仍有独立的方法副本,内存浪费问题仍然存在。
new操作符的工作原理

function myNew(constructor, ...args) { // 1. 创建一个新对象 const obj = {}; // 2. 设置原型链:将新对象的__proto__指向构造函数的prototype obj.__proto__ = constructor.prototype; // const obj = Object.create(Constructor.prototype); // 这种写法也是可以的 // 3. 绑定this并执行构造函数 const result = constructor.apply(obj, args); // 4. 返回结果(如果构造函数返回对象,则返回该对象,否则返回新对象) return result instanceof Object ? result : obj; }

原型模式:解决方法共享问题
原型模式的处理方法是:将方法定义在原型上,实现共享。

function Person(name, age) { // 属性定义在实例上(每个实例独立) this.name = name; this.age = age; } // 方法定义在原型上(所有实例共享) Person.prototype.sayHello = function() { console.log('你好,我是' + this.name + ',今年' + this.age + '岁'); }; Person.prototype.work = function() { console.log(this.name + '正在工作'); }; // 创建实例 const p1 = new Person('张三', 25); const p2 = new Person('李四', 30); p1.sayHello(); // 你好,我是张三,今年25岁 p2.sayHello(); // 你好,我是李四,今年30岁 // 现在方法是共享的! console.log(p1.sayHello === p2.sayHello); // true

原型模式带来的问题

  1. 所有实例都会共享引用类型属性,如果在原型上定义引用类型,一个数据修改时,所有对象对应的数据都会修改
  2. 所有实例共享相同的原型属性,无法动态传递初始化参数

组合继承:结合构造函数和原型的优点
组合继承的实现
组合继承的实现:使用构造函数定义实例属性,使用原型定义共享方法。

function Parent(name) { this.name = name; this.colors = ['red', 'blue']; } Parent.prototype.sayName = function() { console.log(this.name); }; function Child(name, age) { Parent.call(this, name); // 第一次调用:继承实例属性 this.age = age; } Child.prototype = new Parent(); // 第二次调用:继承原型方法 Child.prototype.constructor = Child; // 修复constructor指向

组合继承是JavaScript中最常用的继承模式。

组合继承的缺点
父类构造函数被调用了两次:

  1. Parent.call(this, name);第一次调用:继承实例属性
  2. Child.prototype = new Parent();第二次调用:继承原型方法

寄生组合继承:最理想的继承方式
寄生组合继承的实现

function inheritPrototype(child, parent) { // 创建父类原型的副本 const prototype = Object.create(parent.prototype); // 修复constructor指向 prototype.constructor = child; // 将副本设置为子类的原型 child.prototype = prototype; } // 父类 function Animal(name) { this.name = name; this.colors = ['red', 'blue']; } Animal.prototype.sayName = function() { console.log('我是:' + this.name); }; // 子类 function Dog(name, age) { // 继承实例属性(只调用一次父类构造函数) Animal.call(this, name); this.age = age; } // 继承原型方法(不使用new Parent(),避免第二次调用) inheritPrototype(Dog, Animal); // 添加子类特有方法 Dog.prototype.bark = function() { console.log(this.name + '在叫:汪汪!'); };

Class语法:ES6的语法糖
Class的基本语法

class Person { // 构造函数(对应ES5的构造函数) constructor(name, age) { // 实例属性 this.name = name; this.age = age; this._secret = '这是我的秘密'; // 约定俗成的"私有"属性 } // 实例方法(自动添加到原型上) introduce() { console.log(`大家好,我是${this.name},今年${this.age}岁`); } eat(food) { console.log(`${this.name}正在吃${food}`); } // getter和setter get secret() { return this._secret; } set secret(value) { this._secret = value; } // 静态方法(类方法) static createAnonymous() { return new Person('匿名', 0); } }

Class语法背后的原型原理
Class 语法只是语法糖,底层仍然是原型继承,其本质是一个函数:

class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } // Class实际上是一个函数 console.log(typeof Animal); // function

extends 继承
extends 基本语法
在 ES6 的class语法糖中,通过extends语法糖实现继承。

class Dog extends Animal { constructor(name) { super(name); } speak() { console.log(this.name + ' barks.'); } }

extends 继承的本质
extends继承的本质,就等价于ES5的寄生组合继承:

function AnimalES5(name) { this.name = name; } AnimalES5.prototype.speak = function() { console.log(this.name + ' makes a noise.'); }; function DogES5(name) { AnimalES5.call(this, name); } // 设置原型链 DogES5.prototype = Object.create(AnimalES5.prototype); DogES5.prototype.constructor = DogES5; DogES5.prototype.speak = function() { console.log(this.name + ' barks.'); };

Class的高级特性
类表达式

const MyClass = class { constructor(value) { this.value = value; } getValue() { return this.value; } }; const obj1 = new MyClass(42); console.log(obj1.getValue()); // 42

私有字段

class BankAccount { // 私有字段(以#开头) #balance = 0; constructor(owner) { this.owner = owner; } // 通过公开方法访问私有字段 getBalance() { return this.#balance; } } const account = new BankAccount('张三'); // console.log(account.#balance); // SyntaxError: 属性 "#balance" 在类 "BankAccount" 外部不可访问。 console.log(account.getBalance()); // 500

静态块

class Config { static dbConfig; static apiConfig; // 静态初始化块 static { console.log('初始化静态配置...'); this.dbConfig = { host: 'localhost', port: 3306, username: 'root' }; this.apiConfig = { baseUrl: 'https://api.example.com', timeout: 5000 }; } static getConfig() { return { db: this.dbConfig, api: this.apiConfig }; } }

类的访问器属性

class Temperature { constructor(celsius) { this.celsius = celsius; } get fahrenheit() { return this.celsius * 1.8 + 32; } set fahrenheit(value) { this.celsius = (value - 32) / 1.8; } // 只读属性 get kelvin() { return this.celsius + 273.15; } }

Mixin模式(多重继承的替代方案)

const FlyMixin = (BaseClass) => class extends BaseClass { fly() { console.log(`${this.name} is flying!`); } }; const SwimMixin = (BaseClass) => class extends BaseClass { swim() { console.log(`${this.name} is swimming!`); } }; class Animal { constructor(name) { this.name = name; } eat() { console.log(`${this.name} is eating`); } } // 应用Mixin class Duck extends SwimMixin(FlyMixin(Animal)) { quack() { console.log(`${this.name} says: Quack!`); } }

面向对象编程的演进路线

工厂模式 → 构造函数模式 → 原型模式 → 组合继承 → 寄生组合继承 → Class语法 ↓ ↓ ↓ ↓ ↓ ↓ 创建对象 识别类型 共享方法 结合优点 最优方案 语法糖

结语
面向对象编程是 JavaScript 发展的重要里程碑。理解从工厂模式到 Class 语法的演进过程,不仅能让我们写出更好的代码,还能在遇到问题时快速定位和解决。对于文章中错误的地方或者有任何问题,欢迎在评论区留言讨论!

原文: https://juejin.cn/post/76022596
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 16:10:49

关于ResponseSpecification的讲解

1. 它是什么 ResponseSpecification可以理解为一份针对API返回结果的“标准检查清单”。当向一个网络服务发送请求后,会得到一个回应(Response),这个回应里包含状态码、数据体、响应时间等信息。ResponseSpecification就是预先定…

作者头像 李华
网站建设 2026/4/23 13:17:10

一场家宴,看清一家房企的“长期主义”

西安楼市的舞台上,从不缺少热闹的营销活动。但有一类活动,因其纯粹、温暖且不计短期回报,而显得尤为珍贵——那就是“家宴” 。2026年初,招商林屿缦岛“缦友家宴盛典”的举办,再次将“家宴”这个极具招商特色的IP&…

作者头像 李华
网站建设 2026/4/23 13:07:20

iPhone 13 Pro Max 深度解析:配色外观|核心参数|ProMotion 屏幕|影像与视频|续航与充电|官方维修手册要点|二手验机避坑清单(图文版)

🔥 个人主页: 杨利杰YJlio ❄️ 个人专栏: 《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》 《微信助手》 《锤子助手》 《Python》 《Kali Linux》 《那些年未解决的Windows疑难杂症》 🌟 让…

作者头像 李华
网站建设 2026/4/23 13:03:57

Comsol三相电力变压器温度场流体场耦合计算模型,可以得到变压器稳定运行时内部热点温度及油流...

Comsol三相电力变压器温度场流体场耦合计算模型,可以得到变压器稳定运行时内部热点温度及油流速度分布,提供comsol详细学习资料及模型变压器温升问题一直是电力设备设计的痛点,尤其是油浸式变压器内部的热点温度分布。去年调试某220kV变电站时…

作者头像 李华
网站建设 2026/4/21 21:43:03

摆脱论文困扰! 8个AI论文工具测评:继续教育毕业论文写作全攻略

在当前学术研究日益数字化的背景下,论文写作已成为高校继续教育学员面临的重要挑战。从选题构思到文献综述,从内容撰写到格式调整,每一个环节都可能成为阻碍进度的“拦路虎”。为帮助用户高效应对这些难题,本次测评基于2026年的实…

作者头像 李华