原型链是javascript属性查找时自动执行的运行时路径:obj→object.prototype→null;访问obj.tostring()不报错,因该方法存在于object.prototype,且查找过程遇属性即止,终点为null。

原型链不是“要学的概念”,而是 JavaScript 属性查找时自动发生的路径——你写 obj.method() 就已经在走它了。
为什么访问 obj.toString() 却不报错?
因为 obj 自身没有 toString,但它的 __proto__ 指向 Object.prototype,而后者有这个方法。整个查找链是:obj → Object.prototype → null。
- 所有普通对象的
__proto__默认指向Object.prototype -
Object.prototype.__proto__是null,链在此终止 - 只要中间某一级有该属性,就立即返回,不再继续向上找
- 用
Object.getPrototypeOf(obj)替代非标准的obj.__proto__更稳妥
Student.prototype = new Person() 为什么必须重设 constructor?
执行这句后,Student.prototype 变成了一个 Person 实例,它的 constructor 指向 Person,而不是 Student。这会导致 new Student().__proto__.constructor === Person,破坏构造器标识。
- 必须手动补上
Student.prototype.constructor = Student - 不修复会导致
instance.constructor === Person,影响类型判断和实例重建逻辑 - ES6 class 内部自动处理了这点,但手写原型继承时极易漏掉
为什么组合继承要调两次父类构造函数?
组合继承中,Student.prototype = new Person() 会执行一次 Person 构造函数;而在 Student 构造函数里再用 Person.call(this, ...) 又执行一次。结果是:父类实例属性被初始化两遍,其中一份挂在原型上,白白占用内存。
- 第一次(设置原型):为共享方法准备,但顺带创建了
hobby这类引用类型属性,被所有子类实例共享 - 第二次(call 调用):真正给每个实例分配独立属性
- 典型症状:
stu1.hobby.push('x')会影响stu2.hobby—— 因为它们共用原型上的同一个数组 - 寄生组合式继承(
Object.create(Person.prototype))能避开这个问题
修改原型上的方法,所有实例真的立刻生效吗?
是的,但仅限于「未被实例自身覆盖」的方法。一旦某个实例自己设置了同名属性(比如 stu.sayName = function(){}),后续调用就不再走原型链,原修改对其无效。
- 动态性是原型链的优势,也是隐患:全局改
Array.prototype.map会影响所有代码 - 不要直接修改
Object.prototype或内置构造函数原型,容易引发冲突 - 用
hasOwnProperty可区分属性来源:stu.hasOwnProperty('name')返回true表示是实例自有
真正容易被忽略的,不是怎么写继承,而是忘记原型链本质是「运行时属性查找路径」——它不绑定代码结构,只响应每次属性访问。哪怕你删掉整个 Person.prototype,已存在的实例仍能调用旧方法,直到下一次查找时才失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











