JS 对象遍历及属性判断

677 阅读3分钟

属性判断

说明

可枚举:属性的 enumerable 值为 true

自身属性:未特别说明均为自有可枚举不可枚举属性(非继承属性)

let obj = {
  name: 'orange',
  age: 18
}

// 添加一个不可枚举属性
Object.defineProperty(obj, 'weight', {
    value: 140,
    enumerable: false // 不可枚举
})

// 在原型上添加一个可枚举属性
Object.prototype.height = 180;

// 新增一个值为 undefined 的属性
obj.birthday = undefined;

PS: 下面示例均是基于上方基础代码进行判断的

自有属性(枚举、不可枚举)及继承属性

  • 正常访问属性形式【 .[]
  • in 运算符
console.log(obj.name !== undefined)  // 自身属性存在(true)
console.log(obj['weight'] !== undefined)  // 不可枚举属性(true)
console.log(obj.height !== undefined) // 原型链上继承的属性(true)
console.log(obj.gender !== undefined)  // gender 属性不存在(false)
console.log(obj.birthday !== undefined)  // 值为 undefined 的属性(false)

'name' in obj  // 自身属性(true)
'weight' in obj  // 不可枚举属性(true)
'height' in obj  // 原型链上继承的属性(true)
'birthday' in obj  // 值为 undefined 的属性(true)

注意⚠️

  • 特殊情况,正常访问属性形式如果值为 undefined 的属性,是不会返回预期结果
  • in 运算符对于值为 undefined 的属性也可以进行判断(对像是否含有某属性)
  • 不能准确区分是自有属性还是原型链上的继承属性。如果想要检测自有属性是否存在时,需要使用 Object.hasOwnProperty()

自有属性(枚举、不可枚举)

Object.hasOwnProperty() 判断属性是否为对象自有属性(非继承属性)

obj.hasOwnProperty('name')  // 自身属性(true)
obj.hasOwnProperty('weight')  // 可枚举属性(true)
obj.hasOwnProperty('birthday')  // 值为 undefined 属性(true)

obj.hasOwnProperty('height')  // 原型链上继承的属性(false)

自身属性(可枚举)

Object.keys() 返回对象可枚举自有属性(不含不可枚举、继承和 Symbol 属性)

image-20211231154207177.png

对象遍历

  • 遍历对象 所有自有和继承属性(可枚举),使用 for...in
  • 遍历对象 所有自有属性(可枚举、不可枚举),使用 Object.getOwnPropertyNames()
  • 遍历对象 所有自有 Symbol 属性,使用 Object.getOwnPropertySymbols()
  • 遍历对象 所有自有属性(包含 Symbol 属性),使用 Reflect.ownKeys()
  • 遍历对象 所有自有属性(可枚举),使用 Object.keys()for...in + Object.hasOwnProperty()
  • 获取对象 所有继承属性(可枚举),可以使用 for...in + Object.keys()
  • 获取对象 所有属性(可枚举、不可枚举和继承),使用 for...in + Object.getOwnPropertyNames(obj)for...in + Object.keys() + Object.getOwnPropertyNames(obj)

for...in

遍历对象所有自有和继承的可枚举属性

for (let key in obj) {
  console.log(key, obj[key])
}

image-20211231161008440.png

Object.keys()

遍历对象,返回所有可枚举自有属性(不含 Symbol 属性)值数组

for (key of Object.keys(obj)) {  // 遍历对象 key 值
  console.log(key, obj[key]);
}

image-20211231162157137.png

for...of

遍历所有实现了 Iterator 接口的迭代器对象,主要包含有 ArraySetMap 结构、类数组对象(比如 arguments 对象、DOM NodeList 对象)、字符串等。

注意⚠️:不能直接用来遍历对象

可通过结合 Object.keys(obj)Object.values(obj)Object.entries(obj) 方法先转化再进行遍历

for (value of Object.values(obj)) { // 遍历对象 value 值
  console.log(value); // orange 18 undefined
}

for ([key, value] of Object.entries(obj)) {  // 遍历对象 key、value 值
  console.log(key, value);
}

image-20211231162157137.png

Object.getOwnPropertyNames()

遍历对象,返回所有自有属性(不含 Symbol 属性) key 值数组

Object.getOwnPropertyNames(obj)

image-20211231163740311.png

Object.getOwnPropertySymbols()

遍历对象,返回所有 自有 Symbol 属性 组成的数组

Reflect.ownKeys()

遍历对象,返回所有自有属性(包含 Symbol 属性)组成的数组,等价于:Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(target))

拓展

for...in + Object.getOwnPropertyNames()

获取所有属性名(自有属性及继承属性)

const getAllPropertyNames = (obj) => {
  	// 复制一份所有自有属性
    let props = Object.assign([], Object.getOwnPropertyNames(obj))
    // 得到所有的可枚举属性(自有的和继承的属性)
    for (let key in obj) {
        // 过滤自有的不可枚举属性(获取继承可枚举属性)
        if (!Object.getOwnPropertyNames(obj).includes(key)) {
            props.push(key)
        }
    }
    return props;
};

console.log(getAllPropertyNames(obj);)

image-20211231170454572.png