原型与原型链是什么?属性查找规则怎么走?
面试速答(30 秒版 TL;DR)
- 每个对象都有一个隐藏属性
[[Prototype]](可用Object.getPrototypeOf(obj)读取),指向另一个对象或null。 - 访问属性时:先查对象自身属性,找不到就沿着
[[Prototype]]一层层向上找,直到null,这条链就是原型链。 - 函数(构造器)有
prototype属性:new Foo()创建实例时,会把实例的[[Prototype]]指向Foo.prototype。 - 常见误区:
obj.__proto__是历史非标准接口(现在多数实现仍支持),推荐用标准 API。
心智模型:两条线要分清
实例.__proto__(标准名[[Prototype]])指向“它继承谁”构造函数.prototype指向“实例共享方法放哪”
属性查找(Property Lookup)规则
const obj = { a: 1 };
obj.a; // 先查 obj 自身
obj.toString; // 自身没有 -> 去 Object.prototype 找
查找顺序(面试口述版):
- 查对象自己的属性(含自有属性、访问器属性)。
- 沿
[[Prototype]]去原型对象查。 - 一直查到
null,还没找到就是undefined。
补充:如果是 in 操作符,它会沿原型链判断是否存在:
"toString" in obj; // true(来自原型)
obj.hasOwnProperty("toString"); // false(不是自有属性)
new 发生了什么(高频)
面试常用的“4 步描述”:
- 创建一个空对象
o。 - 设置
o.[[Prototype]] = Foo.prototype。 - 以
o作为this执行构造函数Foo。 - 如果构造函数返回对象则用该对象,否则返回
o。
典型追问
Q1:__proto__ 和 prototype 的区别?
__proto__(或Object.getPrototypeOf):对象实例的原型指针。prototype:函数对象的属性,给new出来的实例当原型用的“共享对象”。
Q2:原型链的终点是什么?
大多数普通对象的终点是 Object.prototype,再往上是 null:
Object.getPrototypeOf(Object.prototype) === null; // true
易错点/坑
- “继承就是复制”:不是。原型继承是“委托查找”,没找到才去原型找。
- 改实例上的同名属性不会改原型:实例会创建/覆盖自己的属性,原型不变。
- 把
__proto__当标准:工程上用Object.getPrototypeOf/Object.setPrototypeOf。
速记要点(可背诵)
- 对象通过
[[Prototype]]形成原型链,属性查找沿链向上。 new Foo()让实例的[[Prototype]]指向Foo.prototype。