首先用一个生活中整理书包的比喻来解释 Reflect.ownKeys,保证你秒懂它的作用和独特之处。
1. 一句话总结
Reflect.ownKeys 就像一把 “万能钥匙”,能一次性拿到对象自身的 所有属性名(包括字符串、Symbol、不可枚举属性),没有遗漏,没有过滤。
2. 对比其他方法(先看场景)
假设你有一个书包(对象),里面装着:
课本(普通字符串属性,比如 name: ‘语文’)
上锁的日记本(不可枚举属性,比如 Object.defineProperty 设置 enumerable: false)
加密U盘(Symbol 类型属性,比如 const key = Symbol(‘secret’))
现在你想彻底清点书包里的所有物品,但不同的清点方式效果不同:
方法 | 能清点到的物品 | 比喻 |
---|---|---|
Object.keys() | 课本 ✅ | 只拿表面看得见的物品 |
for…in 循环 | 课本 + 书包外挂的装饰品(原型链)❌ | 拿自己+别人挂过来的物品 |
Object.getOwnPropertyNames() | 课本 + 上锁的日记本 ✅ | 拿所有字符串属性的物品 |
Object.getOwnPropertySymbols() | 加密U盘 ✅ | 只拿 Symbol 属性的物品 |
Reflect.ownKeys() | 课本 + 上锁的日记本 + 加密U盘 ✅ | 全拿!不管类型和是否隐藏 |
- 代码演示
// 创建一个书包(对象)
const bag = {
book: '语文课本', // 普通字符串属性
};
// 添加一个上锁的日记本(不可枚举属性)
Object.defineProperty(bag, 'diary', {
value: '我的日记',
enumerable: false, // 不可枚举
});
// 添加一个加密U盘(Symbol 属性)
const secretKey = Symbol('secret');
bag[secretKey] = '重要文件';
// 测试不同方法
console.log(Object.keys(bag)); // ["book"]
console.log(Object.getOwnPropertyNames(bag)); // ["book", "diary"]
console.log(Object.getOwnPropertySymbols(bag)); // [Symbol(secret)]
console.log(Reflect.ownKeys(bag)); // ["book", "diary", Symbol(secret)]
4. 为什么深拷贝要用它?
在深拷贝时需要 “原封不动” 复制对象的所有属性,包括:
Symbol 属性(比如 Vue 中的 ob 这类内部标记)
不可枚举属性(比如某些库在对象上添加的隐藏配置)
普通字符串属性
如果只用 Object.keys() 或 for…in,会导致 Symbol 属性和不可枚举属性丢失,拷贝不完整。
5. 技术细节
返回值:数组,包含对象自身的 所有属性名(字符串 + Symbol)。
特性:
- 包含不可枚举属性(enumerable: false)。
- 不包含原型链上的属性。
- 属性名顺序与 Object.getOwnPropertyNames() 一致(先数字升序,再字符串插入顺序)。
6. 适用场景
场景 | 示例 |
---|---|
深拷贝 | 复制对象所有自有属性 |
元编程 | 分析或修改对象的完整属性结构 |
框架开发 | 处理隐藏的 Symbol 属性(如 Vue 响应式标记) |
一句话总结
Reflect.ownKeys 是 JavaScript 中 最彻底的对象属性扫描器,专治各种“隐藏物品”(Symbol、不可枚举属性),保证你的操作不留死角!