writable 控制对象自身属性是否可修改,原型定义影响属性查找路径;属性访问优先级为自身>原型,writable仅约束自身属性赋值,不阻止遮蔽原型属性。

writable 是数据属性的描述符之一,它控制属性值能否被修改;而“原型定义”指的是在构造函数的 prototype 上添加的属性或方法。这两者不属于同一维度——writable 管的是**已有属性的可写性**,原型定义影响的是**属性访问时的查找路径和遮蔽关系**。真正发生“优先级比较”的,是**对象自身属性 vs 原型链上的同名属性**,而 writable 只在这个前提下起作用。
属性访问优先级:自身 > 原型
当读取或写入一个属性时,JavaScript 总是先检查对象自身是否拥有该属性:
- 如果自身有,就直接使用(无论
writable: true还是false) - 如果自身没有,才沿
[[Prototype]]链向上查找,直到Object.prototype或null - 若原型上有同名属性,但自身也有,原型属性会被“遮蔽”,完全不参与访问
writable 只约束“自身属性”的赋值行为
writable: false 的作用非常具体:它只阻止对该对象自身这个属性的重新赋值,不影响原型链查找,也不影响你给对象新增一个同名属性(即“遮蔽”原型属性):
-
Object.defineProperty(obj, 'x', { value: 1, writable: false })→ 后续obj.x = 2无效(严格模式报错,非严格模式静默失败) - 但你可以执行
obj.x = 2成功——只要x原本不在obj自身上,而是在原型上;此时你其实是给obj新增了一个自身的x属性(遮蔽了原型),这个新属性默认writable: true - 换句话说:
writable不阻止“遮蔽”,只阻止“改写已存在的自身属性”
常见误区澄清
有人以为 “原型上定义了 writable: false 的属性,子对象就无法覆盖它”,这是错的:
- 原型上的属性描述符(包括
writable)对实例对象的属性操作没有约束力 - 实例调用
obj.prop = ...时,若prop不在自身,则一定新建自身属性,与原型上该属性是否可写无关 - 只有当你用
Object.defineProperty(obj, 'prop', {...})显式定义自身属性,并设writable: false,才会真正锁住该实例上的赋值
如何验证?
一段可运行代码帮你理清:
const proto = {};
Object.defineProperty(proto, 'flag', {
value: 'fromProto',
writable: false,
enumerable: true
});
const obj = Object.create(proto);
console.log(obj.flag); // 'fromProto'(从原型读取)
obj.flag = 'overridden'; // ✅ 成功!因为 obj 自身无 flag,这行会添加自身属性
console.log(obj.flag); // 'overridden'
console.log(obj.hasOwnProperty('flag')); // true
// 再试一次:自身已有 flag,且 writable: false
Object.defineProperty(obj, 'locked', { value: 1, writable: false });
obj.locked = 99; // ❌ 无效(非严格模式)或报错(严格模式)
console.log(obj.locked); // 1
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











