最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何用 Object.defineProperty 为对象属性设置只读或不可枚举权限
时间:2026-08-07 07:21:49 编辑:袖梨 来源:一聚教程网
如何用 Object.defineProperty 为对象属性设置只读或不可枚举权限并不只看表面做法,关键还要理解相关条件、限制和后续影响。
正确设置只读属性需同时设 writable: false 和 configurable: false;仅 writable: false 时仍可通过 defineProperty 改回可写;enumerable: false 控制遍历可见性,不影响直接访问;Vue 2 中 defineProperty 无法监听新增属性、数组索引赋值等,存在固有局限。
Object.defineProperty 设置只读属性的正确写法
直接设 writable: false 不够,必须同时确保 configurable: false,否则后续仍可通过 Object.defineProperty 重新打开写权限。只设 writable: false 后,属性值确实无法被赋值(严格模式下报 TypeError: Cannot assign to read only property),但只要 configurable: true,就能再次调用 Object.defineProperty 把 writable 改回 true。
实操建议:
- 需要真正只读,必须同时设
writable: false和configurable: false - 若只希望“当前不可写但未来可配置”,才保留
configurable: true(极少用) - 对已存在的普通属性补设只读时,原属性必须是
configurable: true才能成功调用Object.defineProperty
const obj = { a: 1 };Object.defineProperty(obj, 'a', { writable: false, configurable: false, value: 1});obj.a = 2; // 无效(非严格模式)或报错(严格模式)Object.defineProperty(obj, 'a', { writable: true }); // TypeError: Cannot redefine property: a
让属性不可枚举的关键是 enumerable: false
enumerable: false 控制该属性是否出现在 for...in、Object.keys()、JSON.stringify() 等遍历操作中。它和 writable、configurable 正交,可以单独设置,不影响读写行为。
常见误区:
-
enumerable: false不等于“隐藏”——仍可通过obj.prop直接访问,也能用Object.getOwnPropertyDescriptor查到 -
for...in会跳过enumerable: false属性,但会遍历原型链上enumerable: true的属性 -
Object.assign({}, obj)只拷贝自身且enumerable: true的属性,所以enumerable: false属性不会被复制
const obj = {};Object.defineProperty(obj, 'hidden', { value: 'secret', enumerable: false, writable: true, configurable: true});console.log(Object.keys(obj)); // []console.log(obj.hidden); // 'secret'
同时设置只读 + 不可枚举的典型场景
这类组合常用于定义内部状态字段、缓存键、或向库暴露“只读接口但不污染遍历结果”的属性。比如封装一个带缓存的计算属性:
- 缓存值本身不应被外部修改(
writable: false) - 也不应出现在
Object.keys()或序列化中(enumerable: false) - 通常还要禁用重配置(
configurable: false),防止被意外覆盖
注意:如果属性初始值是对象或数组,writable: false 只冻结引用,不深冻结内容;需额外用 Object.freeze。
const cache = {};Object.defineProperty(obj, '_cache', { value: cache, writable: false, enumerable: false, configurable: false});// 后续仍可修改 cache 内部:cache.x = 1;// 若需完全冻结,应写成 value: Object.freeze({})
Vue 2 响应式系统里为什么慎用 Object.defineProperty
Vue 2 用 Object.defineProperty 实现数据劫持,但它有硬性限制:无法检测对象新增/删除属性,也无法监听数组索引赋值(如 arr[0] = x)或 length 变更。这些限制不是写法问题,而是 API 本身能力边界。
实际开发中容易踩的坑:
- 给响应式对象动态加属性(如
vm.obj.newKey = val),不会触发视图更新 - 用
Object.defineProperty手动加的属性,若没走 Vue 的set方法,也不会进入依赖收集 - 数组方法如
push被重写了,但直接写索引或splice某些用法仍可能漏掉响应
现代项目优先用 Proxy 替代,但若维护旧代码,就得接受这些约束,并始终用 Vue.set 或 this.$set 添加响应式属性。
相关文章
- 鹅鸭杀超级金水铃模式怎么玩 08-07
- 牧场物语风之繁华集市生日日期怎么看 08-07
- 口袋新旅途如何捕捉颓颓鹰 08-07
- DNF狄瑞吉版本女漫游加点攻略 08-07
- 鹅鸭杀士兵怎么玩 08-07
- DNF狄瑞吉版本协战师加点攻略 08-07