JavaScript原型链是属性查找的真实路径:对象自身→__proto__→上层原型→…→null,决定方法调用、instanceof及class继承机制;Object.create()安全继承,直接赋值Parent.prototype会污染;引用类型属性被所有实例共享。

JavaScript 原型链不是语法糖,而是属性查找时真实走的一条路径:从对象自身 → __proto__ → 上层原型 → … → null。 它直接决定了 obj.method() 能不能找到、instanceof 为什么返回 true、甚至 class extends 底层怎么跑起来——不理解它,改个方法可能影响所有实例,修个 bug 会绕晕三圈。
为什么访问 obj.toString() 却能在 Object.prototype 上找到?
因为 JavaScript 查属性是“先自己,再往上翻”的硬规则。当你写 obj.toString(),引擎实际执行的是:
- 查
obj自身有没有toString属性(没有) - 查
obj.__proto__(即obj构造函数的prototype)有没有(比如Array.prototype也没有) - 继续查
obj.__proto__.__proto__,也就是Object.prototype(有!) - 停住,返回该方法
这条“向上翻”的链,就是原型链。终点永远是 Object.prototype.__proto__ === null,再往上就查不到,返回 undefined。
Object.create() 和直接赋 Child.prototype = Parent.prototype 有什么区别?
后者是危险操作,前者才是安全继承的标准写法。
立即学习“Java免费学习笔记(深入)”;
-
Child.prototype = Parent.prototype:父子共用同一原型对象。你在Child.prototype.foo = ...,Parent实例也立刻能调用foo——这不是继承,是污染 -
Child.prototype = Object.create(Parent.prototype):创建一个新对象,其__proto__指向Parent.prototype,既复用父方法,又隔离修改空间 - 别漏掉
Child.prototype.constructor = Child,否则new Child()实例的constructor会指向Parent,影响instanceof和调试识别
ES6 class 和 extends 真的“不用管原型”了吗?
不是。Babel 编译后,class B extends A 本质就是两行关键操作:
Object.setPrototypeOf(B.prototype, A.prototype);
B.__proto__ = A;
这意味着:
-
new B()的原型链是:B instance → B.prototype → A.prototype → Object.prototype → null - 但
B构造函数本身并不在A的原型链上(B.__proto__ === A是真,但B instanceof A是假) -
super()必须在子类constructor中第一句调用,否则this未初始化,报错ReferenceError: Must call super constructor...
最常被忽略的点:原型链上的引用类型(如 colors: ['red'])会被所有实例共享。你改一个实例的 this.colors.push('blue'),其他实例看到的数组也变了——这不是 bug,是机制使然,得靠构造函数继承(Parent.call(this))来隔离实例数据。











