在某些情况下我应该使用 in 运算符而不是 hasOwnProperty() 吗?
Are there any cases when I should use the in operator instead of hasOwnProperty()?
在 JavaScript 中,in
运算符检查对象是否具有指定的 属性。但是,它不仅检查对象自身的属性,还检查原型链。因此,在某些情况下,它的行为可能与预期不完全一致。
假设由于某种原因我们有一个对象 someArrayMethods
包含(显然)一些数组方法作为键:
const someArrayMethods = {
indexOf: true,
map: true,
};
我们可以使用 in
运算符检查该对象是否具有特定方法作为键:
console.log('indexOf' in someArrayMethods); // true
console.log('every' in someArrayMethods); // false
如果我们尝试检查 toString
属性 会怎样?
console.log('toString' in someArrayMethods); // true
惊喜!事实证明,这个对象在原型链中有一个 toString
method,所以 in
运算符 returns true
即使对象没有自己的 toString
属性.
这就是 hasOwnProperty()
的救星!它与 in
运算符几乎相同,只有一个区别:它不检查原型链。我们可以重写我们之前的例子:
console.log(someArrayMethods.hasOwnProperty('toString')); // false
现在它按预期工作了。不幸的是,hasOwnProperty()
在一种情况下也会失败。如果我们有一个带有自己的 属性 hasOwnProperty
的对象怎么办?看这个例子:
const someObject = {
hasOwnProperty() {
return false;
},
theAnswer: 42,
};
// Does `someObject` has own property `theAnswer`?
console.log(someObject.hasOwnProperty('theAnswer')); // false
// Well, it seems it doesn't...
为了解决这个问题,我们可以直接从Object.prototype
:
中引用那个方法而不是使用someObject.hasOwnProperty
const hasOwn = Object.prototype.hasOwnProperty;
console.log(hasOwn.call(someObject, 'theAnswer')); // true
这似乎是检查对象是否具有某些 属性 的最合理方法。尽管如此,是否存在 in
运算符有用的情况?我知道它可以用来检查某个 class 的实例是否有某种方法,但在这种情况下,简单地检查该对象是否是那个 class 的实例不是更好吗?
作为旁注,另一种选择是使用 Object.keys()
with ECMAScript 2016 Array.prototype.includes()
:
console.log(Object.keys(someObject).includes('theAnswer')); // true
你回答你自己的问题。
in
当你想在原型链中搜索时也很好。
用于加载 polyfill 的功能检测、使用现代 DOM API 的测试条件等。
使用 in
运算符是评估是否应该 load/execute 一个 JavaScript polyfill 的理想选择,因为它会检查原型链。
例如:
// this works wonderfully
if (!('addEventListener' in window)) {
// polyfill addEventListener
}
相比于:
// this doesn't work at all
if (!window.hasOwnProperty('addEventListener')) {
// polyfill addEventListener
}
因此 the Polyfill.io service 将其用于特征检测测试的原因。
in
是一个运算符,所以不能被劫持。您不必依赖没有脚本被更改或隐藏 Object
、Object.prototype
、Object.prototype.hasOwnProperty
、Object.prototype.hasOwnProperty.call
.
这是一种快速了解对象是否具有某些 属性 的方法。我的意思是,如果 obj.foo
可以 return 例如"bar"
即使 foo
属性 是继承的,能够事先知道 obj
是否具有 foo
属性 也是有意义的, 拥有或继承。
当然,如果我们只有 HasOwnProperty,我们可以(通常)继续调用 [[GetPrototypeOf]] 直到链结束,并检查每个对象。但这对代码来说会很乏味,可能比原生 in
慢,而且在 ES5 之前是不可能的。
而且,还有一个根本的区别。 in
运算符使用 [[HasProperty]] 内部方法,而 HasOwnProperty 使用 [[GetOwnProperty]]。对于非普通对象,迭代 [[GetOwnProperty]] 和 [[GetPrototypeOf]] 可能会产生与 [[HasProperty]] 不同的结果。
所以是的:当你想调用对象的内部 [[HasProperty]] 方法时,in
运算符很有用。事实上,除了Reflect.has
,这是唯一正确的方法。
var p = new Proxy({}, {has: function() {
console.log('Hooray!');
return true;
}});
p.hasOwnProperty('foo'); // :(
'foo' in p; // Hooray! :)
在 JavaScript 中,in
运算符检查对象是否具有指定的 属性。但是,它不仅检查对象自身的属性,还检查原型链。因此,在某些情况下,它的行为可能与预期不完全一致。
假设由于某种原因我们有一个对象 someArrayMethods
包含(显然)一些数组方法作为键:
const someArrayMethods = {
indexOf: true,
map: true,
};
我们可以使用 in
运算符检查该对象是否具有特定方法作为键:
console.log('indexOf' in someArrayMethods); // true
console.log('every' in someArrayMethods); // false
如果我们尝试检查 toString
属性 会怎样?
console.log('toString' in someArrayMethods); // true
惊喜!事实证明,这个对象在原型链中有一个 toString
method,所以 in
运算符 returns true
即使对象没有自己的 toString
属性.
这就是 hasOwnProperty()
的救星!它与 in
运算符几乎相同,只有一个区别:它不检查原型链。我们可以重写我们之前的例子:
console.log(someArrayMethods.hasOwnProperty('toString')); // false
现在它按预期工作了。不幸的是,hasOwnProperty()
在一种情况下也会失败。如果我们有一个带有自己的 属性 hasOwnProperty
的对象怎么办?看这个例子:
const someObject = {
hasOwnProperty() {
return false;
},
theAnswer: 42,
};
// Does `someObject` has own property `theAnswer`?
console.log(someObject.hasOwnProperty('theAnswer')); // false
// Well, it seems it doesn't...
为了解决这个问题,我们可以直接从Object.prototype
:
someObject.hasOwnProperty
const hasOwn = Object.prototype.hasOwnProperty;
console.log(hasOwn.call(someObject, 'theAnswer')); // true
这似乎是检查对象是否具有某些 属性 的最合理方法。尽管如此,是否存在 in
运算符有用的情况?我知道它可以用来检查某个 class 的实例是否有某种方法,但在这种情况下,简单地检查该对象是否是那个 class 的实例不是更好吗?
作为旁注,另一种选择是使用 Object.keys()
with ECMAScript 2016 Array.prototype.includes()
:
console.log(Object.keys(someObject).includes('theAnswer')); // true
你回答你自己的问题。
in
当你想在原型链中搜索时也很好。
用于加载 polyfill 的功能检测、使用现代 DOM API 的测试条件等。
使用 in
运算符是评估是否应该 load/execute 一个 JavaScript polyfill 的理想选择,因为它会检查原型链。
例如:
// this works wonderfully
if (!('addEventListener' in window)) {
// polyfill addEventListener
}
相比于:
// this doesn't work at all
if (!window.hasOwnProperty('addEventListener')) {
// polyfill addEventListener
}
因此 the Polyfill.io service 将其用于特征检测测试的原因。
in
是一个运算符,所以不能被劫持。您不必依赖没有脚本被更改或隐藏 Object
、Object.prototype
、Object.prototype.hasOwnProperty
、Object.prototype.hasOwnProperty.call
.
这是一种快速了解对象是否具有某些 属性 的方法。我的意思是,如果 obj.foo
可以 return 例如"bar"
即使 foo
属性 是继承的,能够事先知道 obj
是否具有 foo
属性 也是有意义的, 拥有或继承。
当然,如果我们只有 HasOwnProperty,我们可以(通常)继续调用 [[GetPrototypeOf]] 直到链结束,并检查每个对象。但这对代码来说会很乏味,可能比原生 in
慢,而且在 ES5 之前是不可能的。
而且,还有一个根本的区别。 in
运算符使用 [[HasProperty]] 内部方法,而 HasOwnProperty 使用 [[GetOwnProperty]]。对于非普通对象,迭代 [[GetOwnProperty]] 和 [[GetPrototypeOf]] 可能会产生与 [[HasProperty]] 不同的结果。
所以是的:当你想调用对象的内部 [[HasProperty]] 方法时,in
运算符很有用。事实上,除了Reflect.has
,这是唯一正确的方法。
var p = new Proxy({}, {has: function() {
console.log('Hooray!');
return true;
}});
p.hasOwnProperty('foo'); // :(
'foo' in p; // Hooray! :)