JavaScript中in和hasOwnProperty的区别

原文:The Difference Between in and hasOwnProperty in JavaScript

JavaScript中检查对象中是否包含指定key的两种方法。

一个普通的JavaScript对象,由两种常见的方法检查对象中是否包含指定的key:运算符inhasOwnProperty()函数。对于简单的没有特殊key的POJO而言,二者是等效的:

1
2
3
4
5
6
const obj = { answer: 42 };
'answer' in obj; // true
obj.hasOwnProperty('answer'); // true

'does not exist' in obj; // false
obj.hasOwnProperty('does not exist'); // false

二者也都支持ES6的symbol

1
2
3
4
5
const symbol = Symbol('answer');
const obj = { [symbol]: 42 };

symbol in obj; // true
obj.hasOwnProperty(symbol); // true

二者的区别是什么呢?主要区别就是in对继承属性返回true,而hasOwnProperty()对继承属性返回false

例如,JavaScript的Object基类有一个__proto__属性,一个constructor属性,和一个hasOwnProperty函数。运算符in对这些属性会返回true,而hasOwnProperty()返回false

1
2
3
4
5
6
7
'constructor' in obj; // true
'__proto__' in obj; // true
'hasOwnProperty' in obj; // true

obj.hasOwnProperty('constructor'); // false
obj.hasOwnProperty('__proto__'); // false
obj.hasOwnProperty('hasOwnProperty'); // false

因为hasOwnProperty()会忽略继承属性,它对POJO(plain old JavaScript object,普通的传统JavaScript对象)而言是更好的选择。但对于ES6类的getter和方法,hasOwnProperty()会返回false,见ES6 getters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class BaseClass {
get baseProp() {
return 42;
}
}
class ChildClass extends BaseClass {
get childProp() {
return 42;
}
}
const base = new BaseClass();
const child = new ChildClass();

'baseProp' in base; // true
'childProp' in child; // true
'baseProp' in child; // true

base.hasOwnProperty('baseProp'); // false
child.hasOwnProperty('childProp'); // false
child.hasOwnProperty('baseProp'); // false

以下是inhasOwnProperty()的对比表。

总之,hasOwnProperty()大多数场景是正确的选择,因为需要避免特殊key问题,比如constructor。一个好的经验法则:如果检查一个对象是否包含某个属性,应该使用hasOwnProperty(),如果检查一个对象是否包含需要调用的函数,例如toString(),应该用in