日常开发的时候我们可能常会用if(obj.a)来判断某个属性是否存在某个对象上面,但是其实是存在缺点的,比如当a为0或者是undefined的时候,会被混淆导致判断的不是很准确
可以使用各种api来进行区分,并且有些属性是存在原型链上面的,某些api可能不支持,有些api可能是通过遍历来找到属性的,那如果属性被修改为不可遍历,则找不到对应的属性
1. 使用属性访问
通过直接访问属性,检查是否为 undefined
。这个可能是用的比较多的方法,但同时也存在缺陷,比用if(obj.a)虽然会好一点
const obj = { a: 1, b: undefined };
console.log(obj.a !== undefined); // true
console.log(obj.b !== undefined); // false (值为 undefined)
console.log(obj.c !== undefined); // false (属性不存在)
缺点: 属性不存在和属性值为
undefined
会被混淆,我们无法判断是不存在还是它的属性值为undefined
2. 使用 in
操作符
const obj = { a: 1 };
console.log('a' in obj); // true
console.log('b' in obj); // false
console.log('toString' in obj); // true (继承自原型)
不能区分属性是对象本身的还是继承自原型链的。无论属性是否存在原型链都会被检测出来。
3. 使用 hasOwnProperty
方法 或 Object.hasOwn
(ES2022+)
const obj = { a: 1 };
console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty('b')); // false
console.log(obj.hasOwnProperty('toString')); // false
检查属性是否直接定义在对象上(不检查原型链)但是不检查原型链,对于不需要原型链属性的场景比较友好
5. 使用 Reflect.has
(ES6)
- 语法:
Reflect.has(object, propertyName)
- 原理:与
in
操作符类似,可检测对象本身和原型链上的属性。
const obj = { a: 1 };
console.log(Reflect.has(obj, 'a')); // true
console.log(Reflect.has(obj, 'b')); // false
console.log(Reflect.has(obj, 'toString')); // true
功能与
in
操作符基本相同。不适用于需要区分自身属性和继承属性的场景。
**6. 使用 Object.keys
**
const obj = { a: 1 };
console.log(Object.keys(obj).includes('a')); // true
console.log(Object.keys(obj).includes('b')); // false
缺点: 如果通过defineProperty设置了不可遍历的话是无法访问到的,下面的代码设置了enumberable为false,表示不可被遍历,由于Objecet.key用的就是遍历,所以会找不到
const obj = { a: 1 ,b:2};
Object.defineProperty(obj,'b',{
value:3,
enumberable:false
})
const keys = Object.keys(obj)
总结
需要根据使用的场景来进行使用,
推荐使用方法
- 现代代码开发:优先使用
Object.hasOwn
,语法清晰且安全。 - 兼容性需求:使用
hasOwnProperty
,确保跨环境兼容。 - 需要检测原型链:使用
in
或Reflect.has
。
注意:不同方法适用于不同场景,开发时需综合考虑代码性能、兼容性和语义清晰度。