要理解 JavaScript 的原型和原型链,咱们用生活化的比喻 +代码示例来拆解,保证你看完能拍着大腿说"原来这么简单!"
一、先想一个问题:对象为什么能"自带"方法?
比如,你创建一个空对象 const cat = {}
,但它却能调用 cat.toString()
(输出 [object Object]
)。明明你没给 cat
写过 toString
方法,它哪来的?
答案: 这些方法是从它的"原型"那里"继承"来的!
二、原型(Prototype):对象的"爸爸"
JavaScript 里的每个对象(除了 null
),都有一个隐藏属性 __proto__
(现代浏览器可直接访问),它指向另一个对象------原型对象(Prototype)。
原型对象就像对象的"爸爸",对象可以从"爸爸"那里继承属性和方法。
举个栗子:
arduino
// 创建一个空对象
const cat = {};
// 查看 cat 的原型(爸爸)
console.log(cat.__proto__);
// 输出:{ constructor: Object, ... } (即 Object.prototype)
cat
的原型是 Object.prototype
(所有对象的"祖宗"),所以 cat
能继承 Object.prototype
里的方法(比如 toString
、hasOwnProperty
)。
三、构造函数:批量生产对象的"工厂"
如果你想批量创建类似的对象(比如很多猫),可以用构造函数。
构造函数是专门用来"生产对象"的函数,它的 prototype
属性(注意是大写的 P
)就是它生产的所有对象的"原型"(爸爸)。
举个栗子:
javascript
// 定义一个"猫"的构造函数
function Cat(name) {
this.name = name; // 每个猫实例的私有属性
}
// 给 Cat 的原型(爸爸)添加一个方法(所有猫都能继承)
Cat.prototype.meow = function() {
console.log(`${this.name}:喵喵~`);
};
// 生产猫实例
const tom = new Cat("Tom");
const luna = new Cat("Luna");
// tom 和 luna 都能调用 meow 方法(从原型继承的)
tom.meow(); // Tom:喵喵~
luna.meow(); // Luna:喵喵~
// 查看实例的原型(爸爸)
console.log(tom.__proto__ === Cat.prototype); // true!
console.log(luna.__proto__ === Cat.prototype); // true!
-
关键点 :所有通过
new Cat()
生成的实例(tom
、luna
),它们的__proto__
都指向Cat.prototype
(构造函数的原型对象)。 -
好处 :不用给每个猫单独写
meow
方法,只需要写在原型上,所有实例共享同一个方法,省内存!
四、原型链(Prototype Chain):找属性/方法的"寻亲链"
当你访问一个对象的属性或方法时(比如 tom.name
或 tom.eat
),JavaScript 会按以下顺序找:
-
先看对象自己有没有这个属性/方法(
tom
自己的name
)。 -
如果没有,就去它的原型(
tom.__proto__
,即Cat.prototype
)里找。 -
如果还没有,就去原型的原型(
Cat.prototype.__proto__
,即Object.prototype
)里找。 -
直到找到
null
(所有链的终点),如果还没找到,就报错。
这条层层查找的"链条",就是原型链。
举个栗子:
javascript
// 给 Object.prototype 加一个方法(所有对象都能继承)
Object.prototype.sayHi = function() {
console.log("你好呀!");
};
const tom = new Cat("Tom");
// tom 自己没有 sayHi,但原型链能找到:
tom.sayHi(); // 你好呀!(来自 Object.prototype)
// 查看原型链关系:
console.log(tom.__proto__ === Cat.prototype); // true(爸爸)
console.log(Cat.prototype.__proto__ === Object.prototype); // true(爷爷)
console.log(Object.prototype.__proto__); // null(祖先)
- 原型链示意图 :
tom → Cat.prototype → Object.prototype → null
五、总结:原型和原型链的本质
-
原型(Prototype) :对象的"爸爸",存储可被继承的属性和方法(通过
构造函数.prototype
定义)。 -
原型链(Prototype Chain) :对象找属性/方法时的"寻亲路径",通过
__proto__
层层连接,直到null
。 -
核心目的 :实现对象的属性/方法共享 ,避免重复代码(比如所有对象都能用
toString
)。
一句话记住:
原型是"爸爸",原型链是"家族族谱",对象找东西时,会顺着家族族谱往上翻,直到找到或翻到最顶头的空白页(null
)。
明白了吗?同学,今天又进步了。加油,未来可期。