先看一个例子
var person = { name:undefined}console.log(person.name); // undefinedconsole.log(person.age); // undefined
上面的例子中 person对象有一个name属性,没有age属性。但是,使用
person.name 和 person.age访问属性值时,两者的结果都是undefined。
因此我们没法通过值为undefined来判断一个对象是否有某个属性。
那么如何判断一个对象是否存在一个属性。
1. in 操作符
如果指定的属性存在对象或其原型链中,那么in
操作符返回true 。
注意: in操作符判断属性的存在性,不论属性是否可枚举
举个例子:
let man = { speak: 'I can'}// 已man对象为原型创建person对象let person = Object.create(man);//定义person对象的name属性,该属性是person对象的自有属性person.name='noshower';//定义person对象的自有属性,但是'age'不可枚举,Object.defineProperty(person, 'age', { enumerable: false, configurable: true, writable: true, value: 23});console.log('speak' in person); // trueconsole.log('name' in person); // trueconsole.log('age' in person); // trueconsole.log('job' in person); // false
因为job不存在person中,也不存在person对象的原型链上,所以结果为false。
再看个例子:
var array = new Array('a','b','c','d','e');delete array[3]; console.log(3 in array); // falseconsole.log(array.length); // 5
从这个例子中看出,当删除数组的某个下标后,数组下标确实不存在了。但是没有改变数组的长度。只是该位置被空出来了而已。
2. hasOwnProperty
如果对象自身属性中存在指定的属性,那么hasOwnProperty
()方法将会返回true,否则返回false。
注意:
hasOwnProperty
不会检查对象原型链上的属性。hasOwnProperty
不论属性是否可以枚举hasOwnProperty
方法存在于Object.prototype
上,因此只要对象的原型链上存在Object.prototype
, 就可以直接访问hasOwnProperty
方法。有点对象(通过Object.create(null)
创建的对象)没有连接到Object.prototype
,那么就无法访问到hasOwnProperty
方法。JavaScript 没有保护
hasOwnProperty
属性名,因此,任何对象都可以使用hasOwnProperty这个名字作为属性名。上述两点,所以可必要使用
Object.prototype.hasOwnProperty.call(obj,prop)
这种形式判断某个属性的存在, 这样就无需担心obj上是否存在hasOwnProperty方法或者hasOwnProperty被覆盖的问题。
举个例子:
let man = { speak: 'I can'}let person = Object.create(man); person.name='noshower';Object.defineProperty(person, 'age', { enumerable: false, configurable: true, writable: true, value: 23});console.log(person.hasOwnProperty('speak')); // falseconsole.log(person.hasOwnProperty('name')); // trueconsole.log(person.hasOwnProperty('age')); // trueconsole.log(person.hasOwnProperty('job')); // false
因为speak属性存在于原型链上,所以返回false。
因为name属性是自有属性,所以返回true。
因为age属性是自有属性,虽然该属性不可枚举,但结果还是true。
因为job属性不存在,所以没有false。
3. for...in 循环
for...in 循环用来遍历对象的可枚举属性,包括原型链上的
注意:
for..in 循环以任意顺序迭代一个对象的属性,不同浏览器遍历属性的顺序可能不同。 因此,最好不要在迭代中对对象进行添加、修改或删除属性。
不要使用for..in遍历数组
for...in不会返回不可枚举的属性
举个例子:
let man = { speak: 'I can'}let person = Object.create(man); person.name='noshower';Object.defineProperty(person, 'age', { enumerable: false, configurable: true, writable: true, value: 23});for(let prop in person){ console.log(prop); // name , speak (并不一定是这样的输出顺序)}
其中age属性没有遍历得到,因为它是不可枚举的。
4. propertyIsEnumerable
如果一个属性是对象的自有属性(直接定义在对象上的)且该属性可枚举,那么 propertyIsEnumerable
方法返回true,否则返回false。
举个例子:
let man = { speak: 'I can'}let person = Object.create(man); person.name='noshower';Object.defineProperty(person, 'age', { enumerable: false, configurable: true, writable: true, value: 23});console.log(person.propertyIsEnumerable('speak')); //falseconsole.log(person.propertyIsEnumerable('name')); // trueconsole.log(person.propertyIsEnumerable('age')); // false
5. Object.keys()
Object.keys()
方法会返回一个由给定对象的所有自身可枚举属性组成的数组。
注意:
Object.keys() 返回的属性是可枚举的
Object.keys()返回的属性是对象的自有属性
结果数组中属性名的排列顺序和使用 for ...in循环遍历该对象时返回的顺序一致
举个例子:
let man = { speak: 'I can'}let person = Object.create(man); person.name='noshower';Object.defineProperty(person, 'age', { enumerable: false, configurable: true, writable: true, value: 23});console.log(Object.keys(person)); // [ 'name' ]
6. Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
方法会返回一个数组,包含所有自有属性,无论它们是否可枚举。
注意:
返回的是自有属性
不论是否可枚举
不包括Symbol值作为名称的属性
数组中可枚举属性的顺序与通过for...in循环(或Object.keys)迭代该对象属性时一致。数组中不可枚举属性的属性未定义。
举个例子:
let man = { speak: 'I can'}let person = Object.create(man); person.name='noshower';Object.defineProperty(person, 'age', { enumerable: false, configurable: true, writable: true, value: 23});console.log(Object.getOwnPropertyNames(person)); //[ 'name', 'age' ]
7.自定义函数:getOwnInnumerablePropertyNames
getOwnInnumerablePropertyNames 只获取对象自身的所有不可枚举属性
function getOwnInnumerablePropertyNames (obj){ //返回对象的所有自有属性,包括不可枚举的 let props = Object.getOwnPropertyNames(obj); //返回对象的所有可枚举属性 let propsEnum = Object.keys(obj); // 过滤出所有不可枚举的 return props.filter(function(key){ return propsEnum.indexOf(key) === -1; }) }
参考文献
《你不知道的JavaScript 上卷》
作者:我待前端如初恋
链接:https://www.jianshu.com/p/c75992ee7b2c