Javascript 对象的循环遍历
这是我参与更文挑战的第3天,活动详情查看: 更文挑战
一、对象的遍历方法
for ... in
Object.keys(), Object.values(), Object.entries()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Reflect.ownKeys()
二、对象属性遍历次序规则
以上5种方法遍历对象的属性时都遵守同样的属性遍历次序规则
- 属性名为数值,按照数值升序排序
- 属性名为字符串,按照生成时间升序排序
- 属性名为Symbol,按照生成时间升序排序
三、遍历方法对比
遍历方法 | 自身属性 | 继承属性 | 可枚举性 | Symbol类型 |
---|---|---|---|---|
for ... in | 自身 | 继承 | 可枚举 | 不包含 |
Object.keys() | 自身 | 可枚举 | 不包含 | |
Object.getOwnPropertyNames() | 自身 | 可枚举和不可枚举 | 不包含 | |
Object.getOwnPropertySymbols() | 自身 | 所有Symbol属性 | ||
Reflect.ownKeys() | 自身 | 可枚举和不可枚举 | 包含 |
四、遍历方法举例
以下的测试都是基于下面给出的对象,对象的属性特性已进行配置。
对于属性名为 Attr_X-X 的属性,
两个数字分别代表是否是自身属性和是否可枚举
第一个X表示———— 0:对象本身的属性 1:对象原型上的属性
第二个X表示———— 0:不可枚举 1:可枚举
let tep_0_0 = Symbol(`tep_0_0`)
let tep_0_1 = Symbol(`tep_0_1`)
let tep_1_0 = Symbol(`tep_1_0`)
let tep_1_1 = Symbol(`tep_1_1`)
let obj = {
"name_0-1": `Happy_0-1`,
"fruit_0-1": `Apple_0-1`,
"country_0-1": `China_0-1`,
"name_0-0": `Happy_0-0`,
"fruit_0-0": `Apple_0-0`,
"country_0-0": `China_0-0`,
[tep_0_0]: `miracle_0-0`,
[tep_0_1]: `miracle_0-1`,
hello_0_1(){
console.log(`fun_0-1`)
},
hello_0_0(){
console.log(`fun_0-0`)
}
}
obj.__proto__ = {
"name_1-1": `Happy_1-1`,
"fruit_1-1": `Apple_1-1`,
"country_1-1": `China_1-1`,
"name_1-0": `Happy_1-0`,
"fruit_1-0": `Apple_1-0`,
"country_1-0": `China_1-0`,
[tep_1_0]: `miracle_1-0`,
[tep_1_1]: `miracle_1-1`,
hello_1_1(){
console.log(`fun_1-1`)
},
hello_1_0(){
console.log(`fun_1-0`)
}
}
Object.defineProperty(obj, "name_0-0", {
value: "Happy_0-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "fruit_0-0", {
value: "Apple_0-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "country_0-0", {
value: "China_0-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "name_1-0", {
value: "Happy_1-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "fruit_1-0", {
value: "Apple_1-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "country_1-0", {
value: "China_1-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, tep_0_0, {
value: "miracle_0-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, tep_1_0, {
value: "miracle_1-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "hello_0_0", {
value: "miracle_0-0",
writable: true,
enumerable: false,
configurable: true,
}
)
Object.defineProperty(obj, "hello_1_0", {
value: "miracle_1-0",
writable: true,
enumerable: false,
configurable: true,
}
)
for in
// 未进行过滤
for (let key in obj) {
console.log(obj[key])
}
// 已进行过滤
for (const i in obj) {
if (Object.prototype.hasOwnProperty.call(obj, i)) {
console.log(obj[i]);
}
}
总结
for in 循环会遍历对象自身和继承的可枚举属性,不包含Symbol属性。
如果只需要对象自身的属性,可以通过 Object.prototype.hasOwnProperty()
进行过滤。
Object.keys
console.log(Object.keys(obj))
总结
ES5 引入了 Object.keys 方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性(不含 Symbol 属性)的键名。
ES2017 引入了跟Object.keys配套的 Object.values
和 Object.entries
,作为遍历一个对象的补充手段,供for...of循环使用。
这三种方法可以访问到的属性是相同的,只是分别返回了 属性名, 属性值, [属性名,属性值]键值对
Object.getOwnPropertyNames()
console.log(Object.getOwnPropertyNames(obj))
总结
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.Object.getOwnPropertySymbols()
console.log(Object.getOwnPropertySymbols(obj))
总结
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
Reflect.ownKeys()
console.log(Reflect.ownKeys(obj))
总结
Reflect.ownKeys返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。