原型属性与实例属性本质区别在于归属位置和共享机制:实例属性在构造函数内定义、各实例独有;原型属性在prototype上定义、所有实例共享,同名时实例属性屏蔽原型属性。

原型对象和实例属性本质不同,不是“谁多谁少”的问题,而是“归属位置”和“共享机制”的差异。对比它们,核心是看清属性在哪定义、被谁访问、是否可修改。
看定义位置:实例属性在构造函数里,原型属性在 prototype 上
实例属性写在构造函数内部,每次 new 都新建一份;原型属性挂在构造函数的 prototype 对象上,所有实例共用一个。
- 实例属性示例:
this.name = 'Tom'; this.count = 0;—— 每个实例都有独立副本 - 原型属性示例:
Person.prototype.sayHi = function() {...}; Person.prototype.age = 25;—— 所有 person 实例共享同一个sayHi函数和age值
看访问行为:同名时实例属性会屏蔽原型属性
当实例自身有某个属性,而原型上也有同名属性,读取时总是优先取实例上的;写入时默认也只改实例自身(不会影响原型)。
-
person1.age = 20;→person1自身多了age,person2.age仍取原型上的 25 -
console.log(person1.age); // 20(来自实例)console.log(person2.age); // 25(来自原型) - 删掉实例属性后,自动回退到原型:
delete person1.age; console.log(person1.age); // 25
看检测方式:用 hasOwnProperty 区分归属
想确认某个属性是不是“自己身上”的,不能靠 in(它查整条原型链),必须用 hasOwnProperty。
-
person1.hasOwnProperty('name') → true(实例定义) -
person1.hasOwnProperty('sayHi') → false(原型定义) -
'sayHi' in person1 → true(存在,但不一定是自己的)
看内存与数据类型:引用类型尤其要注意
实例属性若保存数组、对象等引用值,每个实例独占一份;原型上的引用值则被所有实例共享——这是最易出错的地方。
- 错误示范:
function Car() {} Car.prototype.tags = [];→ 所有 car 实例往tagspush 都操作同一数组 - 正确做法:把
tags放进构造函数:this.tags = [];,确保每个实例独立


















