如何可靠地检查对象是EcmaScript 6 Map/Set?

nac*_*son 8 javascript collections dictionary set ecmascript-6

我只是想检查的对象是MapSet,而不是一个Array.

检查我正在使用lodash的数组_.isArray.

function myFunc(arg) {
  if (_.isArray(arg)) {
    // doSomethingWithArray(arg)
  }

  if (isMap(arg)) {
    // doSomethingWithMap(arg)
  }

  if (isSet(arg)) {
    // doSomethingWithSet(arg)
  }
}
Run Code Online (Sandbox Code Playgroud)

如果我要实现isMap/ isSet,它需要看起来像什么?我希望它能够捕获Map/的子类,Set如果可能的话.

Ber*_*rgi 18

这种情况类似于ES5之前的方法,可以正确可靠地检测数组.请参阅这篇伟大的文章,了解可能存在的实施缺陷isArray.

我们可以用

  • 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于常见用途,我建议instanceof- 它简单,易懂,高效,适用于大多数合理的情况.或者你马上去打鸭子,只检查对象是否有has/ get/ set/ delete/ add/ delete方法.


Poi*_*nty 5

您可以使用instanceof运算符:

function isSet(candidate) {
  return candidate instanceof Set;
}
Run Code Online (Sandbox Code Playgroud)

如果候选对象Set.prototype在其原型链中,则instanceof运算符返回true

编辑- 虽然这instanceof件事在大多数情况下都会起作用,但在某些情况下它不会起作用,如 Bergi 的回答中所述。