if(对象中的键)或if(object.hasOwnProperty(key)


176

以下两个语句是否产生相同的输出?有什么理由比另一种更喜欢一种方式吗?

 if (key in object)

 if (object.hasOwnProperty(key))

Answers:


185

小心-它们不会产生相同的结果。

intrue如果key原型链中某处被找到,也会返回;而Object.hasOwnProperty(就像名称已经告诉我们的那样),只会返回true如果key直接在该对象上可用(它“拥有”该属性)。


3
你到底是什么意思in will also return true if key gets found somewhere in the prototype chain?你可以写一个例子吗?谢谢。
罗兰·伯纳德

44
@Lor:({foo:"bar"}).hasOwnProperty("toString")vs"toString" in ({foo:"bar"})
我讨厌懒惰的

68

我尝试用另一个例子来解释。假设我们有以下具有两个属性的对象:

function TestObj(){
    this.name = 'Dragon';
}
TestObj.prototype.gender = 'male';

让我们创建TestObj的实例:

var o = new TestObj();

让我们检查对象实例:

console.log(o.hasOwnProperty('name')); // true
console.log('name' in o); // true

console.log(o.hasOwnProperty('gender')); // false
console.log('gender' in o); // true

结论:

  • 如果对象可以直接或从原型访问属性,则in运算符始终返回true

  • hasOwnProperty()仅在实例存在属性但原型不存在属性时才返回true

如果要逻辑上检查原型上是否存在某些属性,我们会说:

console.log(('name' in o) && !o.hasOwnProperty('name')); //false
console.log(('gender' in o) && !o.hasOwnProperty('gender')); //true - it's in prototype

最后:

因此,关于声明这两个条件...

if (key in object)
if (object.hasOwnProperty(key))

...产生相同的结果,答案很明显,这取决于。



26

总之,hasOwnProperty()不看原型而in看原型。

取自O'Reilly高性能Javascript

您可以使用hasOwnProperty()方法并传入成员名称来确定对象是否具有给定名称的实例成员。要确定对象是否可以访问具有给定名称的属性,可以使用in运算符。例如:

var book = {
    title: "High Performance JavaScript",
    publisher: "Yahoo! Press" 
};

alert(book.hasOwnProperty("title"));  //true
alert(book.hasOwnProperty("toString"));  //false
alert("title" in book); //true 
alert("toString" in book); //true

在此代码中,当title传入时,hasOwnProperty()返回true,因为title是一个对象实例;传入“ toString”时,该方法返回false,因为该实例上不存在该字符串。当每个属性名称与in运算符一起使用时,两次结果均为true,因为它会搜索实例和原型。


7

您得到了一些非常好的答案。我只想提供一些东西,可以省去迭代对象时检查“ hasOwnProperty”的需要。

通常,创建对象时,人们会以这种方式创建它:

const someMap = {}
// equivalent to: Object.create(Object.prototype)
// someMap.constructor will yield -> function Object() { [native code] }

现在,如果要遍历“ someMap”,则必须采用以下方式:

const key
for(key in someMap ){
 if (someMap.hasOwnProperty(key)) { 
   // Do something
 }
}

我们这样做是为了避免迭代继承的属性。

如果打算创建一个仅用作“映射”(即键-值对)的简单对象,则可以这样做:

const newMap = Object.create(null);
// Now, newMap won't have prototype at all.
// newMap.constructor will yield -> undefined

因此,现在可以像这样进行迭代了:

for(key in cleanMap){
 console.log(key + " -> " + newMap [key]);
 // No need to add extra checks, as the object will always be clean
}

在这里学到了这个很棒的技巧



2

另一种形式(要求in)枚举对象的属性名称(或键)。在每次迭代中,对象的另一个属性名称字符串将分配给变量。通常需要测试object.hasOwnProperty(variable)以确定属性名称是真正的对象成员还是在原型链上找到。

 for (myvar in obj) {
     if (obj.hasOwnProperty(myvar)) { ... } }

(摘自Crockford的Javascript:The Good Parts


5
in运营商比不同的for-in说法。
我讨厌懒惰的2012年

实际上,它们都是in关键字的不同用法
Jahan 2012年

4
是的,in是一个关键字。但是OP正在询问in操作员的具体用法。您的答案是for-in语句中其他用法的一部分。
我讨厌懒惰的2012年

-4

第一个版本较短(尤其是在最小化代码中将变量重命名的版本)

a in b

b.hasOwnProperty(a)

无论如何,正如@AndreMeinhold所说,它们并不总是产生相同的结果。


1
将其作为注释会更好。:-)
Hlawuleka MAS
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.