JavaScript面向对象编程入门:从面向过程到封装实战
本文从面向过程编程切入,通过ATM取款等生活案例解释执行流程,进而引入JavaScript中的封装概念。详细讲解了如何使用构造函数定义类、利用prototype定义行为,并通过new关键字实例化对象。对比了面向过程与面向对象在代码复用和维护上的差异,帮助初学者理解OOP核心思想及属性与行为的声明方式。
JavaScript封装与面向对象编程概述
大家好,此前我们已梳理了JavaScript的基础知识。从本期开始,我们将深入探讨封装技术,逐步触及面向对象编程(OOP)的核心。如果开发者对OOP一无所知或仅停留在概念层面,无法编写出符合面向对象规范的代码,那么深入学习的意义将大打折扣。下文将详细解析面向对象与面向过程的区别,明确二者定义是理解OOP的前提。需注意的是,并非所有场景都适用OOP,若仅解决简单问题,盲目追求面向对象反而徒增复杂度,此时采用面向过程的代码更为高效,即所谓“因地制宜”。
面向过程:从生活案例理解执行流程
首先从面向过程入手,解析“过程”的含义。通常所说的“程序”本质上即是一系列执行步骤的集合。以“上班”为例,这是一个完整的过程:9点准时到岗,完成既定任务,无论结果如何,下午6点下班离开,这一系列动作构成了过程。再看一个更具体的案例:取款,其执行流程如下:
1、携带银行卡前往ATM机
2、将银行卡插入读卡口
3、输入个人密码
4、输入取款金额
5、ATM机出钞
6、将现金收入口袋
7、若未取出期望金额,返回第4步重新操作
8、如需打印回执单则点击打印;若不需要则跳过此步
9、取出银行卡
10、流程结束
由前述步骤可知,从首步至末步即为执行顺序,其中第4至第6步构成循环过程,第7步为分支过程,此即程序之流程。编写代码旨在模拟各类行为过程,借助计算机的高速运算能力以服务于日常生活。
函数封装与参数的重要性
我们可以将取款这一系列动作封装为一个函数,使其成为一个独立的过程单元。在需要时调用该函数即可完成任务。下面通过一个最简示例来演示这一过程:
function KissWife(whoseWife){
console.log(whoseWife+"把脸凑过来");
console.log("我把嘴唇印上去");
console.log("木啊一声");
console.log("亲"+whoseWife+"一次完成");
}
KissWife("我老婆");

结合图示,在适当时机调用KissWife函数并传入合适参数,即可执行完一个完整的过程。
面向对象编程(OOP)的核心目的是提高代码复用率,以最少代码实现最大功能。使用参数正是体现这一思想的典型方式。举一个反面案例:若不使用参数,每次想要执行类似操作时,都需重新编写一个新的KissWife函数。这将导致大量重复代码,增加管理难度,降低代码流畅度,甚至可能因逻辑冗余引入不必要的风险。
此时可能有读者疑问:如果不习惯使用参数,不传递参数,代码管理会有何不便?这个问题非常关键。
对此进行解释:如果在执行过程中发现逻辑不合理需要修改,例如增加某些功能,我们需要修改所有类似的函数(如针对不同对象的函数)。当存在大量相似函数时,逐一修改不仅繁琐(工作量随数量增加而倍增),而且极易因修改次数过多导致遗漏或出错。这充分说明,仅编写重复性代码会严重降低工作效率。
对象概念与类的封装
通过上述讲解,若新手仍对OOP感到困惑,我们将从“对象(object)”概念入手。这里的对象并非仅指人际关系中的伴侣,而是指世间万物,如太阳、大海、人类、宠物等。任何我们所能构想的事物均可视为对象,每个对象都具备自身的属性和行为。

理解方式可参考上图:以“鸟”为例,它是一个对象,拥有特定属性及行为。下面通过具体代码封装一个关于鸟的类。(注:在JavaScript中,function关键字既用于定义函数也可用于定义类,它不像某些高级语言那样提供Class关键字。后续讲解继承时,我们将介绍实现继承的特殊方法。)
//声明一个鸟类
function Bird(){
this.name = "鸽子";
this.color = "灰色";
this.habitat = "笼子";
this.weight = "500克";
}
//使用原型链的方式,来定义鸟的行,也可以用来定义属性,但是,属性一般用this关键字来声明
//行为和属性,其实同一个级别的,后面我们用for in来给大家验证
//鸣叫
Bird.prototype.Sing = function(){
console.log("咕咕咕");
}
//进食
Bird.prototype.Eat = function(){
console.log("吃了一粒玉米");
}
//飞翔
Bird.prototype.Fly = function(){
console.log("在天空中飞翔着");
}
//孵蛋
Bird.prototype.Brood = function(){
cossole.log("正在孵化鸽子蛋");
}
实例化与属性行为声明
现在类已声明完毕,但如何使用它?目前它仅是一个类定义,尚未成为实例。所谓实例,即具体存在的个体,如一只具体的“鸽子”。如何获得具体实例?见下方代码:
//用new 关键字来获得一个实例
var gezi = new Bird();
通过上述方式,我们可以调用对象的属性及方法。

通过此类方法生成的每一个鸽子实例在初始状态下是相同的。若要生成具有独特特征的鸽子,关键在于属性值的差异化。因此,我们需要改造函数的声明方式:
//其实我们只需要在这里小小地修改一下
function Bird(_color,_habitat,_weight){
this.name = "鸽子";
this.color = _color;
this.habitat = _habitat;
this.weight = _weight;
}
接着查看实例化鸽子时的具体操作:
//我们现在就实例化了两个鸽子
var gezi_A = new Bird("白色","野外","300克");
var gezi_B = new Bird("灰白色","温室","550克");

如此,我们便能构造出具有独特特征的鸽子实例。从上述示例可以看出,封装的本质是将可描述的对象抽象为类,随后通过new关键字实例化出具体对象。该对象拥有独立的属性和行为,便于后续操作。封装作为体现OOP思想的方法,先封装类,再通过new生成实例,相比直接编写多次构造代码,大幅减少了代码量。若需构造第3只鸽子,只需再次执行new操作即可,仿佛只需一行代码。这显著提高了代码复用率,OOP的优势由此显现。
面向对象与面向过程代码对比
此时有人提问:仅说明了OOP的好处,未展示不使用OOP的代码写法。下面以鸽子为例,展示非面向对象(面向过程)的写法:
//声明一个鸽子
function GeZi_C(){
console.log("种类是鸽子");
console.log("颜色是蓝色");
console.log("住在树梢上");
console.log("体重400克");
console.log("在天空中飞翔着");
}
//执行一次
GeZi_C();

若需声明100个鸽子,是否要编写大量重复且类似的代码?这就是面向过程代码的典型特征。相信新手朋友对OOP已有一个模糊的概念。这种理解需要时间沉淀,非一日之功。后续我们将继续探讨OOP思想中的继承与多态。
原型链与对象属性验证
回顾前文声明Bird类时提到的点:属性和行为处于同一层级,且有两种声明方式。属性在构造函数内通过this关键字声明,行为函数则通过prototype关键字声明。prototype是函数原型链的标准扩展,我们采用这种方式旨在将JavaScript的使用纳入高级语言的范畴,模拟高级语言的特性。言归正传,我们先验证Bird实例对象中是否确实拥有同层级的属性与行为函数。
//我们现在是用的前面的没有参数的Bird类
var obj = new Bird();
//逐一打印出来
for(var pro in obj){
console.log(pro + " : " + obj[pro]);
}

如前所示,for...in语句用于循环遍历对象属性及数组下标。行为函数的名称实质上也是对象的属性,这验证了前述观点。相信大家对OOP的封装思想已有一定认知。
总结今日内容:我们将事物进行抽象模拟,把属性和行为封装为类,利用new关键字实例化出具体对象。此举极大提高了代码复用率与工作效率。
JS split切割后出现空字符串怎么过滤
2026-11-05 16:00:30
在 React 或 Vue 项目中封装使用 JS 节流防抖
2026-11-05 15:27:29
JavaScript中怎么将带小数的字符串转为整数?
2026-11-05 14:32:38
怎么用JavaScript策略模式重构电商促销计算逻辑?
2026-11-05 14:01:09
JS使用constructor判断数据类型可靠吗
2026-11-05 13:49:41
相关标签:
