小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
获取对象的属性,是非常常规的操作。经常用于复制和拷贝对象,亦或是数据合并,或者判断属性是否存在,然后进行下一步的操作。
for in
可遍历原型上的属性键,不可枚举的属性和Symbol属性除外。
for of
可遍历原型上的属性值,包含不可枚举属性值,不能遍历原型上的值。
Object.keys
返回的是所有可枚举属性键,也就是属性下的enumerable: true。但不包括Symbol值作为名称的属性键。
Object.getOwnPropertyNames
回的是对象所有自己的属性键 ,包括不可枚举属性但不包括Symbol值作为名称的属性键。
Object.getOwnPropertySymbols
方法返回一个给定对象自身的所有 Symbol 属性键的数组。
Reflect.ownKeys
返回一个由目标对象自身的属性键组成的数组。等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
表格对比
for of一般不能直接遍历对象,所以就单独说。
| 方法名 | 普通属性 | 不可枚举属性 | Symbol属性 | 原型属性 |
|---|---|---|---|---|
| for in | ✔ | ✘ | ✘ | ✔ |
| Object.keys | ✔ | ✘ | ✘ | ✘ |
| Object.getOwnPropertyNames | ✔ | ✔ | ✘ | ✘ |
| Object.getOwnPropertySymbols | ✘ | ✔ | ✔ | ✘ |
| Reflect.ownKeys | ✔ | ✔ | ✔ | ✘ |
- for of 获得的是属性值,不是属性键
- 能遍历到原型属性的只有 for in
- Reflect.ownKeys 综合来看是最强大的
- for of一般不能遍历对象,,如果实现了Symbol.iterator,可以遍历。 如Array,Map,Set,String,TypedArray,arguments 对象等等
一起看一个例子:
const symbolSalary = Symbol.for("salary");
const symbolIsAnimal = Symbol.for("isAnimal");
const symbolSay = Symbol.for("say");
function Person(age, name){
this.age = age;
this.name = name;
this.walk = function () {
console.log("person:walk");
}
}
// 原型方法
Person.prototype.say = function(words){
console.log("say:", words);
}
Person.prototype[symbolSay] = function(words){
console.log("symbolSay", words);
}
// 原型属性
Person.prototype[symbolIsAnimal] = true;
Person.prototype.isAnimal = true;
const person = new Person(100, "程序员");
person[symbolSalary] = 6000;
person["sex"] = "男";
// sex 不可枚举
Object.defineProperty(person, "sex", {
enumerable: false
});
Object.defineProperty(person, symbolSalary, {
enumerable: false, // 无效的设置
value: 999
});
const keys = Object.keys(person);
const names = Object.getOwnPropertyNames(person);
const symbols = Object.getOwnPropertySymbols(person);
const ownKeys = Reflect.ownKeys(person);
console.log("keys", keys); // [ 'age', 'name', 'walk' ]
console.log("getOwnPropertyNames", names); // [ 'age', 'name', 'walk', 'sex' ]
console.log("getOwnPropertySymbols", symbolSalary); // [ Symbol(salary) ]
console.log("ownKeys", ownKeys); // [ 'age', 'name', 'walk', 'sex', Symbol(salary) ]
console.log("--------")
console.log(person.isAnimal); // true
console.log(person[symbolIsAnimal]); // true
console.log(person[symbolSalary]); // 999
person[symbolSay]("hello world"); // symbolSay hello world
person.say("hello world"); // say: hello world
person.walk(); // person:walk
综合来看Relect.ownKeys功能强大,能取到Symbol和普通属性,不可枚举的属性也能获取。
但属性复制的时候经常采用的是 for in + Object.hasOwnProperty 双层判断。
现在你觉得那种方式更合适呢?
小结
今天你收获了吗?