在 JavaScript 开发中,我们常常需要判断在于一个对象中一个属性是否存在。
由于 JavaScript 是一个比较松散的语言,导致我们很难去做一些比较严格的事。就比如这个问题,“属性是否存在”在 JavaScript 里的定义出现了偏差,到底什么时候是存在,什么是算不存在。这没有对错之分,只是在不同的语境下,不同的开发需求下,“存在”的含义是不一样的。
这里我就说一说比较常用的5种判断方式,和它们存在的问题。
这里举个例子:
const obj1 = { name: 'Andy', age: 21 } const obj2 = { name: 'Alice' } console.log( obj1.age ? '存在' : '不存在' ); // 存在 console.log( obj2.age ? '存在' : '不存在' ); // 不存在
先说说这种方式的缺陷吧
如果:
const obj = { name: 'Baby', age: 0 } console.log( obj.age ? '存在' : '不存在' ); // 不存在
这种情况下,age应是 “存在”,但是会被判断成“不存在”。
那么这种方式是不是就不能用呢?
这就要根据业务的开发需求了。
如果你知道在你的业务开发需求里,这个属性是不可能为0,空字符串啊,NaN啊,undefined之类的,那么这个判定还是可行的。
如果你放在更加严格的环境,那么这个方式就有缺陷的。
还是先举例:
const obj1 = { name: 'Andy', age: 21 } const obj2 = { name: 'Alice' } console.log( obj1?.age !== undefined ? '存在' : '不存在' ); // 存在 console.log( obj2?.age !== undefined ? '存在' : '不存在' ); // 不存在
这个对比的逻辑就是,在JS语言里,一个不存在的值就是undefined。
但是在一个对象里,也可能出现的这种情况:
const obj = { name: 'Andy', age: undefined }
像这种情况,那么age这个属性应该是“存在”呢,还是“不存在”?
这也就不好说了,还是要看你的具体的需求环境。
如果说,我就要知道一个对象里有没有一个属性age,我不管它的值是什么。
我们就可以用这个方式:
const obj = { name: 'Andy', age: 21 } console.log( Object.keys(obj).includes('age') ? '存在' : '不存在' ); // 存在
使用Object.keys()可以得到自身的可枚举属性名来进行判断。
这里有两个关键词,一个是“自身的”(own),一个是“可枚举”(enumerable)。
比方说这里有一个对象,给对象加一个属性name:
const obj = { name: 'Andy' } // `name` 就是 obj 自身的属性 console.log( Object.keys(obj) ); // [ 'name' ]
那么什么不是自身的属性呢?这里就要扯到“原型”了。一个对象是有原型,在原型上加的属性就不是“自身的”属性了。
const obj = Object.create( { type: 'human' } ); obj.name = 'Andy'; console.log( obj.name ); // Andy console.log( obj.type ); // human console.log( Object.keys(obj) ); // [ 'name' ]
这个例子,你怎么判断type是不是obj的属性呢?这就不好说了对吧,你可以说是,也可以说不是。这就是语言宽松环境带来的问题。
但你需要知道的是,在这种情况下,Object.keys()是拿不到原型上的属性。因为它只能读取“自身的”属性。
这里就要提到属性描述符了,我很多同事都不知道,在JS语言里,在一个对象里,每个属性都有一个描述符的。
怎么读取呢?我们打印看吧:
const obj1 = { name: 'Andy', age: 21 } const obj2 = { name: 'Alice' } console.log( obj1.age ? '存在' : '不存在' ); // 存在 console.log( obj2.age ? '存在' : '不存在' ); // 不存在
你会发现,这个描述符其实也是一个对象,它描述了这个属性的一些信息,比如说值(value),可重写(writable),还有这个(enumerable)可枚举 ...
这个enumerable定义了那个属性,是否可以被枚举,比如for...in循环时候可以读取这个属性,Object.keys()也是如此。
如果我重新定义一个属性为不可枚举的,那么Object.keys()就读取不到这个属性了。
const obj = { name: 'Baby', age: 0 } console.log( obj.age ? '存在' : '不存在' ); // 不存在
这里就涉及到了属性描述符的相关知识了,这个是原生JS语言非常重要的知识,而我发现很多我认识的前端程序员都缺乏这种原生JS的知识。
那么如果说你要判断的属性要求只要是自身的属性,不管可不可枚举呢?那么就不能用Object.keys()了。可以用接下来的方法。
Object.hasOwn() 和 hasOwnProperty() 有什么区别呢?
Object.hasOwn() 是 ES2022 加入的方法,用于检查对象是否自身具有某个属性,用于替代 hasOwnProperty 的促优处理。由于这是后来加入的方法,兼容性还是个问题,如果只考虑新版本的浏览器还是可以用的。
这两个方法判断的是 “自身的” 属性名,所以不管是不是可枚举,都能被读取。
const obj1 = { name: 'Andy', age: 21 } const obj2 = { name: 'Alice' } console.log( obj1?.age !== undefined ? '存在' : '不存在' ); // 存在 console.log( obj2?.age !== undefined ? '存在' : '不存在' ); // 不存在
为什么要用Object.hasOwn(),由于对象的hasOwnProperty()有可能被修改:
const obj = { name: 'Andy', age: undefined }
如果你要判断的属性名,不要求是自身的和可枚举,原型也行,那么就要用最后一个方法了。
in 运算符用于判断一个属性是否存在于对象或其原型链中。
const obj = { name: 'Andy', age: 21 } console.log( Object.keys(obj).includes('age') ? '存在' : '不存在' ); // 存在
这些方法种,没有说那个方法是正确的,那个错误的。并不是每个场景都适合同一种方法,根据情况遵守最佳实践,以增强代码可读性和安全性。
以上是[每次突破] JavaScript 如何判断属性是否存在的详细内容。更多信息请关注PHP中文网其他相关文章!