if(键入对象)或if(object.hasOwnProperty(key)

Lor*_*ard 164 javascript

以下两个语句是否产生相同的输出?有没有理由偏向另一种方式?

 if (key in object)

 if (object.hasOwnProperty(key))
Run Code Online (Sandbox Code Playgroud)

And*_*old 175

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

in也将返回true如果key被在某处找到原型链,而Object.hasOwnProperty(好像是这个名字已经告诉我们),将只返回true,如果key是可用的对象上直接(其"拥有"的属性).

  • @Lor:`({foo:"bar"}).hasOwnProperty("toString")`vs`"toString"in({foo:"bar"})` (44认同)
  • 如果在原型链中的某个地方发现了密钥,那么你的意思是什么呢?你能写一个例子吗?谢谢. (3认同)

Dal*_*bor 64

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

function TestObj(){
    this.name = 'Dragon';
}
TestObj.prototype.gender = 'male';
Run Code Online (Sandbox Code Playgroud)

让我们创建TestObj的实例:

var o = new TestObj();
Run Code Online (Sandbox Code Playgroud)

我们来检查对象实例:

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

console.log(o.hasOwnProperty('gender')); // false
console.log('gender' in o); // true
Run Code Online (Sandbox Code Playgroud)

结论:

  • 如果对象可以直接或从原型访问属性,则运算符中的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
Run Code Online (Sandbox Code Playgroud)

最后:

那么,关于声明这两个条件......

if (key in object)
if (object.hasOwnProperty(key))
Run Code Online (Sandbox Code Playgroud)

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


xav*_*ard 26

in还将检查继承的属性,但情况并非如此hasOwnProperty.


Eti*_*oël 24

总而言之,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
Run Code Online (Sandbox Code Playgroud)

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


asa*_*fel 5

你有一些非常好的答案.我只想提供一些能够在迭代对象时省去检查"hasOwnProperty"的东西.

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

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

现在,如果你想迭代"someMap",你将不得不这样做:

const key
for(key in someMap ){
 if (someMap.hasOwnProperty(key)) { 
   // Do something
 }
}
Run Code Online (Sandbox Code Playgroud)

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

如果您打算创建一个仅用作"地图"(即键 - 值对)的简单对象,您可以这样做:

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

所以现在迭代就像这样安全:

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

在这里学到了很棒的提示