很多初学者一听“面向对象 OOP”,脑袋直接嗡的一声 ——
类?继承?实例?构造函数?prototype?原型链???
但其实只需要跟着 加菲猫 学一遍,你就会发现:
JavaScript 的对象系统其实一点都不复杂,它只是跟加菲猫一样 —— 看起来慵懒,背后却有一套自己的“独门体系”。
今天我们一起从最轻松的方式重新理解 JS 的对象模型:
从创建一只猫开始 🐱
一、对象字面量:做一只“手搓”的加菲猫
最开始的加菲猫,当然是一个字面量对象:
const cat = {
name: '加菲猫',
color: '橘色'
};
很简单对吧?
但如果你需要 一百只猫 呢?
const cat1 = { ... };
const cat2 = { ... };
const cat3 = { ... };
写到你想变成猫。
🐱 加菲:我建议你写个机器,不要真的手搓 100 次。
于是我们开始需要“封装”。
二、构造函数:开一家“猫咪加工厂” 🏭
构造函数就是一个 能生产实例的工厂:
function Cat(name, color) {
this.name = name;
this.color = color;
}
用它制造猫:
const cat1 = new Cat('加菲猫', '橘色');
const cat2 = new Cat('黑猫警长', '黑色');
new 这个小东西非常关键,JS 会为我们偷偷做四件事:
- 创建一个空对象
{} - 将这个对象绑定给
this - 执行构造函数,把属性都挂到这个新对象上
- 返回这个对象
所以:
const cat1 = new Cat('tom', '黑色');
就等于 👇
“生成一只叫 tom 的黑色猫”。
三、问题出现:每只猫都复制一套方法,太胖了🐱💥
假设你在构造函数里写方法:
function Cat(name, color) {
this.name = name;
this.color = color;
this.eat = function() {
console.log("吃 jerry");
}
}
每 new 一只猫,就复制一份 eat(),100 只猫就 100 份,
JS 内存都快被猫咪吃光了。
🐱 加菲:我很胖,但代码不能跟我一样胖。
于是,JS 给你准备了“共享仓库”—— prototype。
四、prototype:所有猫共享的大仓库 🏬
prototype 的作用是:
放所有 不会改变、可以共享 的方法。
改写如下:
function Cat(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype.eat = function() {
console.log('吃 jerry');
};
Cat.prototype.type = '猫科动物';
现在:
- 每只猫自己的属性:
name/color - 所有猫共享的方法:
eat/type
检验一下:
cat1.hasOwnProperty('type') // false
cat1.type // 从原型里找
🐱 加菲:我自己的东西我自己保存,共同的东西放在仓库里,大家共享多合理。
五、原型链:猫咪的“家谱系统” 🧬
当你访问 cat1.eat,JS 会:
- 先看“自己家”有没有(实例)
- 没有就去找“父亲”(prototype)
- 再没有继续往上一代(Object.prototype)
- 最后到
null
这条查找路线,就是 原型链 prototype chain。
如果把对象想象成猫咪:
cat1 → Cat.prototype → Animal.prototype → Object.prototype → null
每一代都可能存着猫咪的祖传本领。
六、继承:让猫继承动物的属性 🐱 → 🐯
先来动物类:
function Animal() {
this.species = '动物';
}
Animal.prototype.sayHi = function() {
console.log('哪哪哪啦');
}
让 Cat 继承 Animal 的属性:
function Cat(name, color) {
// 继承实例属性
Animal.apply(this);
this.name = name;
this.color = color;
}
然后让 Cat 继承 Animal 的方法:
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
现在 cat 就是一只名副其实的动物:
const cat = new Cat('加菲猫', '橘色');
cat.species // 动物
cat.sayHi() // 哪哪哪啦
🐱 加菲:谢谢你让我终于在户口本上变成“动物”了。
七、ES6 class:更好看的“猫咪工厂”包装纸 🎁
ES6 的 class 并没有改变 JS 本质(底层还是原型),但写起来更开心:
class Cat {
constructor(name, color) {
this.name = name;
this.color = color;
}
eat() {
console.log('吃 jerry');
}
}
继承更简单:
class Animal {
constructor() {
this.species = '动物';
}
sayHi() {
console.log('哪哪哪啦');
}
}
class Cat extends Animal {
constructor(name, color) {
super(); // 等同于 Animal.apply(this)
this.name = name;
this.color = color;
}
}
🐱 加菲:穿上 ES6 的新衣服,我更帅了,但骨子里还是那只加菲猫。
八、掌握 JS OOP,只需要记住这套“加菲猫口诀”🐱📜
🌟 口诀 1:构造函数是工厂
new 会自动创建对象 + 绑定 this + 初始化属性。
🌟 口诀 2:共有的放 prototype
不变的、可复用的都放到 prototype,省内存。
🌟 口诀 3:原型链是家谱
查属性顺序:实例 → 原型 → 原型的原型 → ... → null。
🌟 口诀 4:继承分两步
- 继承属性:
apply/super() - 继承方法:改变子类的 prototype 指向
🌟 口诀 5:class 只是语法糖
背后还是构造函数 + prototype。
🎉 最后:JS 的 OOP,其实没那么难
只要你理解:
- 构造函数是生产猫的工厂
- prototype 是共享仓库
- 原型链是猫咪的家谱
- 继承是把父类的属性方法嫁接过来
你就已经真正掌握了 JavaScript 的 OOP 核心。