Javascript 如何可靠地检查对象是否为EcmaScript 6映射/集?
我只想检查对象是否是Javascript 如何可靠地检查对象是否为EcmaScript 6映射/集?,javascript,dictionary,collections,set,ecmascript-6,Javascript,Dictionary,Collections,Set,Ecmascript 6,我只想检查对象是否是映射或集合,而不是数组 function myFunc(arg) { if (_.isArray(arg)) { // doSomethingWithArray(arg) } if (isMap(arg)) { // doSomethingWithMap(arg) } if (isSet(arg)) { // doSomethingWithSet(arg) } } 要检查数组,我正在使用lodash的\uu.isArray
映射
或集合
,而不是数组
function myFunc(arg) {
if (_.isArray(arg)) {
// doSomethingWithArray(arg)
}
if (isMap(arg)) {
// doSomethingWithMap(arg)
}
if (isSet(arg)) {
// doSomethingWithSet(arg)
}
}
要检查数组,我正在使用lodash的\uu.isArray
function myFunc(arg) {
if (_.isArray(arg)) {
// doSomethingWithArray(arg)
}
if (isMap(arg)) {
// doSomethingWithMap(arg)
}
if (isSet(arg)) {
// doSomethingWithSet(arg)
}
}
如果我要实现
isMap
/isSet
,它需要什么样的外观?如果可能的话,我希望它能够捕获Map
/Set
的子类。您可以使用instanceof
操作符:
function isSet(candidate) {
return candidate instanceof Set;
}
如果候选对象在其原型链中有Set.prototype
,则instanceof
操作符返回true
编辑-虽然
instanceof
在大多数情况下都能正常工作,但正如Bergi的回答所述,在某些情况下它不能正常工作。这种情况类似于ES5之前正确可靠地检测阵列的方法。有关实现isArray
的可能陷阱,请参阅
function myFunc(arg) {
if (_.isArray(arg)) {
// doSomethingWithArray(arg)
}
if (isMap(arg)) {
// doSomethingWithMap(arg)
}
if (isSet(arg)) {
// doSomethingWithSet(arg)
}
}
我们可以使用
/obj.constructor==Map
,但这对子类实例不起作用(并且很容易被欺骗)Set
/obj instanceof Map
,但这仍然不能跨领域工作(并且可能会被原型损坏所欺骗)Set
/obj[Symbol.toStringTag]=“Map”
,但这很容易再次被欺骗“Set”
[[MapData]]
/[[SetData]]]
内部插槽。这是不容易访问-它的内部。不过,我们可以使用黑客:
function isMap(o) {
try {
Map.prototype.has.call(o); // throws if o is not an object or has no [[MapData]]
return true;
} catch(e) {
return false;
}
}
function isSet(o) {
try {
Set.prototype.has.call(o); // throws if o is not an object or has no [[SetData]]
return true;
} catch(e) {
return false;
}
}
对于常见用途,我建议使用instanceof
——它简单易懂,性能优良,适用于大多数合理的情况。或者,您立即进行duck键入,只检查对象是否具有has
/get
/set
/delete
/添加
/删除
方法。您可以简单地使用:
export function isMap(item) {
return !!item && Object.prototype.toString.call(item) === '[object Map]';
}
export function isSet(item) {
return !!item && Object.prototype.toString.call(item) === '[object Set]';
}
除非该方法的原型被覆盖否则,即使该集合是
集合
的子类,该方法是否仍有效?我应该说明的是,这是一个值得关注的问题。@nackjicholson这取决于您如何创建子类。如果构造函数的.prototype
位于对象的prototype链中,则instanceof
运算符返回true
。@nackjicholson:只要您执行类MySet extensed Set
,就可以。请注意,如果您正在为将重新分发的库编写代码,最好先检查是否定义了window.Set
(除非您的库中包含适用于旧浏览器的垫片)。(或者,为了使它也能在服务器上工作,您可以检查设置的类型!=“undefined”
)。是的。事实上,这种情况更糟糕,因为与数组不同,集合只在最新的规范中使用。在较旧的浏览器中使用垫片是很常见的,我刚刚意识到Object.prototype.toString
检查对这些浏览器不起作用。我可能会在这里发布一个最终的答案。为什么不使用Object.prototype.toString.call(o)='[objectset]'
?除了有人重写Object.prototype.toString
之外,还有其他情况会失败吗?(我不认为重写的Object.prototype.toString
值得担心-这是一种会破坏许多现有库的糟糕做法。)@MattBrowneObject.prototype.toString
相当于使用符号.toString
方法-您不需要重写全局,它可以在每个对象的基础上进行处理。是否严格需要布尔检查?似乎可以在没有的情况下使用falsy值。是的,这是必需的,因为在项上调用object.toString,如果它未定义或为null,它将在Chrome和Firefox中为对象.prototype.toString.call(null)
调用对象时抛出错误。