JavaScript学习笔记:对象属性检测
JavaScript对象可以看作是一个属性的集合,很多时候需要看某个属性是否存在于某个对象中。在JavaScript中对象属性的检测主要有以下几种方法。
in运算符
hasOwnProperty()方法
propertyIsEnumerable()方法
!==undefined
接下来看这四种方法怎么检测对象属性。
in运算符
使用in运算符可以检测对象属性,如果指定的属性存在于指定的对象中,就会返回true,反之返回的是false。
下面的例子演示了in是如何检测对象属性的。
varmyCar={
'make':'Honda',
'model':'Accord',
'year':1998
}
'make'inmyCar;//true
'name'inmyCar;//false
'toString'inmyCar;//true
在使用in运算符做对象属性检测时,运算符右侧必须是一个对象,比如可以是一个string包装的对象,但不能是一个字符串原始值。
varname=newString('w3cplus');
'length'inname;//true
'w3cplus'inname;//false
//Chrome输出
name=>String{0:"w",1:"3",2:"c",3:"p",4:"l",5:"u",6:"s",length:7,[[PrimitiveValue]]:"w3cplus"}
typeofname=>object
varname='w3cplus';
'length'inname;//false
'w3cplus'inname;//false
//Chrome输出
name=>"w3cplus"
typeofname=>string
使用delete运算符删除了一个对象一个属性,这时使用in运算符检测删除的属性时会返回false:
varobj={
'name':'w3cplus',
'type':'blog'
}
deleteobj.name;//Object{type:"blog"}
nameinobj;//false
如果你只是将一个属性的值赋值为undefined,而没有用delete删除它,这个时候使用in运算符检测对象属性时依旧会返回true。
varobj={
'name':'w3cplus',
'type':'blog'
}
obj.url=undefined;
'url'inobj;//true
hasOwnProperty()方法
使用hasOwnProperty()方法可以判断某个对象是否含有指定的自身属性。使用这个方法,所有承继继承了Object.prototype的对象都会从原型链上继承到hasOwnProperty()方法上。而且该方法会忽略掉那些从原型上继承到的属性。
如果对象obj包含指定的prop属性的话,使用hasOwnProperty()方法将返回true值,反之将会返回false。
先来看个简单示例:
varobj={
'name':'w3cplus',
'type':'blog'
}
obj.hasOwnProperty('name');//true
obj.hasOwnProperty('toString');//false
只有hasOwnProperty()可以给出正确和期望的结果,这在遍历对象的属性时会很有用。没有其它方法可以用来排除原型链上的属性,而不是定义在对象自身上的属性。
hasOwnProperty()方法只会查找自身属性,不会根据原型链进行查找。而且hasOwnProperty()方法在碰到对象拥有自已的hasOwnProperty方法时,其原型链上的同名方法hasOwnProperty()就会被遮蔽。
varfoo={
hasOwnProperty:function(){
returnfalse;
},
bar:'Herebedragons'
};
foo.hasOwnProperty('bar');//始终返回false
如果担心hasOwnProperty()方法有可能被遮蔽的这种情况,可以直接使用原型链上真正的hasOwnProperty方法:
({}).hasOwnProperty.call(foo,'bar');//true
Object.prototype.hasOwnProperty.call(foo,'bar');//true
propertyIsEnumerable()方法
propertyIsEnumerable()方法是hasOwnProperty()方法的一个升级版。在JavaScript中每个对象都有一个propertyIsEnumerable()方法。使用这个方法可以判断出指定的对象obj里的属性prop是否可枚举,也就是说该属性是否可以通过for...in循环遍历到,不过有些属性虽然可以通过for...in循环遍历到,但因为它们不是自身属性,而是从原型链上继承的属性,所以该方法也会返回false。如果对象没有指定的属性,该方法返回false。
先来看一个propertyIsEnumerable()方法在普通对象和数组上的基本用法:
varobj={};
obj.name='w3cplusiswebsite';
obj.type='blog';
obj.propertyIsEnumerable('name');//true
obj.propertyIsEnumerable('type');//true
obj.propertyIsEnumerable(0);//false
obj.propertyIsEnumerable('toString');//false
!==undefined
还有一种简单的方法可以判断对象的属性是否存在,通过属性!==undefined来判断。此时会检测自身和继承来的属性。之所以使用!==而不是!=是因为!==可以区分undefined和null。但是此方法有一个弊端,当属性存在且值为undefined时,无法做出准确判断。如:
varobj={
x:"1",
y:undefined,
z:null
};
console.log(obj.x!==undefined);//true属性存在
console.log(obj.y!==undefined);//false此时会出现歧义,不能准确判断属性是不存在还是属性值为undefined
console.log(obj.z!==undefined);//true属性存在
console.log(obj.z!=undefined);//false!=不能区分undefined和null,将两者同等对待
console.log(obj.w!==undefined);//false属性不存在
console.log(obj.toString!==undefined);//true存在toString函数属性。
然而有一种场景只能使用in运算符,而不能使用上述属性访问的方式。in可以区分不存在的属性和存在的属性但其值为undefined。如下面的代码所示:
varobj={
x:undefined//属性显式赋值为undefined
}
obj.x!==undefined;//false,属性存在,但值为undefined
obj.y!==undefined;//false,属性不存在
"x"inobj;//true属性存
"y"inobj;//false属性不存在
deleteobj.x;//删除属性x
"x"inobj;//false属性不存
总结
上面简单的整理了几种对象属性检测的方法,下面简单的做一下相关的总结:
in自身存在的属性,继承的属性,返回true
hasOwnProperty()自身存在的属性返回true,继承属性返回false
propertyIsEnumerable()自身存在的属性,且为枚举属性返回true,
!==undefined自身存在的属性,继承的属性,不能识别值为undefined的属性