什么是原型(prototype)
每个函数在出生时就自带一个属性:
函数名.prototype —— 它是一张空对象,浏览器里叫 Foo.prototype。
每个对象在出生时也自带一个“隐姓埋名”的属性:
对象.proto(规范名 [[Prototype]]),它指向自己构造函数的 prototype。
用处:让所有实例共享一份方法/数据,省内存 + 能动态升级。
一、没有原型时:方法满天飞,内存爆炸
JavaScript
复制
function User(name) {
this.name = name
this.sayHi = function () { // 每个实例都新建一份
console.log(Hi, ${this.name}
)
}
}
const u1 = new User('Tom')
const u2 = new User('Jerry')
console.log(u1.sayHi === u2.sayHi) // false ➜ 100 万个用户就 100 万份函数
内存示意图:
复制
u1 : { name: 'Tom', sayHi: <func obj#1> }
u2 : { name: 'Jerry',sayHi: <func obj#2> } // 两份完全一样的代码
二、把方法挂到原型上:只存一份,所有实例自动可用
function User(name) {
this.name = name // 实例私有属性
}
// 公有方法 → 原型仓库
User.prototype.sayHi = function () {
console.log(Hi, ${this.name}
)
}
const u1 = new User('Tom')
const u2 = new User('Jerry')
console.log(u1.sayHi === u2.sayHi) // true ➜ 同一份函数
u1.sayHi() // Hi, Tom
u2.sayHi() // Hi, Jerry
内存示意图:
u1 : { name: 'Tom', proto -> User.prototype }
u2 : { name: 'Jerry',proto -> User.prototype } // 指向同一份
↕
User.prototype : { sayHi: <func obj#1> }
原型链
当读取 对象.属性 时:
1.先看对象自身有没有;
2.没有 → 沿 proto 去原型对象找;
3.再没有 → 原型的原型(proto 的 proto)……
4.直到 null 为止,这条链式查找路径就叫原型链。
u1.proto → Foo.prototype → Foo.prototype.proto → Object.prototype → null
作用 = 复用方法、实现继承、属性共享、instanceof 判断。