以下两个语句是否产生相同的输出?有没有理由偏向另一种方式?
if (key in object)
if (object.hasOwnProperty(key))
答案 0 :(得分:170)
小心 - 它们不会产生相同的结果。
如果在{em>原型链的某处找到in
, true
也会返回key
,而Object.hasOwnProperty
(就像名字已经告诉我们的那样) ),如果true
直接在该对象上可用(它“拥有”该属性),则仅返回key
。
答案 1 :(得分:59)
我试着用另一个例子来解释。 假设我们有以下两个属性的对象:
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
结论:
始终返回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))
...产生相同的结果,答案很明显,这取决于。
答案 2 :(得分:26)
in
还会检查继承的属性,hasOwnProperty
不是这种情况。
答案 3 :(得分:22)
总而言之,hasOwnProperty()
不会查看原型,而in
会查看原型。
取自O'Reilly High Performance 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是一个对象实例;该方法在返回false时返回false 传入“toString”,因为它在实例上不存在。什么时候 每个属性名称与in运算符一起使用,结果为true 这两次都是因为它搜索了实例和原型。
答案 4 :(得分:5)
你有一些非常好的答案。 我只想提供一些能够在迭代对象时省去检查“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
}
我学到了这个很棒的提示here
答案 5 :(得分:2)
另一个表单(要求输入)枚举属性名称(或键) 一个对象。在每次迭代时,另一个属性名称字符串来自 对象被分配给变量。 通常需要进行测试 object.hasOwnProperty(变量)判断属性名称是否为 是真正的对象成员,或者被发现在原型链上。
for (myvar in obj) {
if (obj.hasOwnProperty(myvar)) { ... } }
(来自Crockford的 Javascript:The Good Parts )
答案 6 :(得分:-4)
第一个版本更短(特别是在重命名变量的缩小代码中)
a in b
vs
b.hasOwnProperty(a)
无论如何,正如@AndreMeinhold所说,他们并不总能产生相同的结果。