writable 是数据属性的内部特征,仅作用于当前对象自身属性描述符,不参与原型链查找;属性访问时只检查最终找到的属性所在对象的 writable 值,遮蔽可绕过原型的 writable 限制。

writable 是数据属性的内部特征之一,控制该属性值能否被重新赋值。它**不参与原型链查找,只作用于当前对象自身的属性描述符**;继承链中对 writable 的影响,本质是“属性是否可写”取决于**访问到的那个具体属性所在的对象及其描述符**,而非原型链本身。
属性查找与 writable 无关
JavaScript 属性访问遵循“自身 → 原型链向上”的查找规则,但 writable 并不随查找过程传递或叠加。引擎只检查最终找到的那个属性所在对象上的描述符:
- 如果属性在实例上存在,就看实例上该属性的
writable值(默认true) - 如果属性在原型上找到,就看原型对象上该属性的
writable值 - 即使原型属性
writable: false,只要实例上定义了同名属性(遮蔽),赋值操作就只作用于实例属性,不受原型限制
遮蔽(Shadowing)会绕过原型的 writable 限制
当子对象自身拥有同名属性时,它会遮蔽原型上的属性——此时无论原型属性是否 writable: false,赋值都成功且仅修改实例属性:
const proto = {};
Object.defineProperty(proto, 'x', { value: 10, writable: false });
const obj = Object.create(proto);
console.log(obj.x); // 10(从原型读取)
obj.x = 20; // ✅ 成功:在 obj 上创建新属性 x = 20(遮蔽)
console.log(obj.x); // 20(实例属性)
console.log(obj.__proto__.x); // 10(原型属性未变)
直接修改原型属性值受其 writable 控制
若尝试对“未被遮蔽”的继承属性赋值(即属性只存在于原型上),则实际是在修改原型对象上的那个属性,此时 writable 生效:
- 非严格模式下:
writable: false时赋值静默失败(无报错,值不变) - 严格模式下:
writable: false时赋值抛出TypeError
'use strict';
const proto = {};
Object.defineProperty(proto, 'y', { value: 100, writable: false });
const obj = Object.create(proto);
obj.y = 200; // ❌ TypeError: Cannot assign to read only property 'y'
构造函数 + prototype 场景中的典型表现
常见误区:以为 Person.prototype.name = 'default' 定义的属性受 writable 保护。实际上,这种字面量赋值等价于:
Object.defineProperty(Person.prototype, 'name', {
value: 'default',
writable: true, // ⚠️ 默认为 true!
enumerable: true,
configurable: true
});
所以除非显式设 writable: false,否则通过 instance.name = 'new' 总是能覆盖原型上的值——但这其实是遮蔽,不是修改原型属性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











