你如何检查一个 JavaScript 对象是否是一个 DOM 对象?

IT技术 javascript dom object
2021-01-29 20:51:44

我试图得到:

document.createElement('div')  //=> true
{tagName: 'foobar something'}  //=> false

在我自己的脚本中,我曾经只使用它,因为我从不需要tagName作为属性:

if (!object.tagName) throw ...;

因此,对于第二个对象,我想出了以下作为快速解决方案的方法——它大多有效。;)

问题是,这取决于浏览器强制执行只读属性,但并非所有人都这样做。

function isDOM(obj) {
  var tag = obj.tagName;
  try {
    obj.tagName = '';  // Read-only for DOM, should throw exception
    obj.tagName = tag; // Restore for normal objects
    return false;
  } catch (e) {
    return true;
  }
}

有什么好的替代品吗?

6个回答

这可能是有趣的:

function isElement(obj) {
  try {
    //Using W3 DOM2 (works for FF, Opera and Chrome)
    return obj instanceof HTMLElement;
  }
  catch(e){
    //Browsers not supporting W3 DOM2 don't have HTMLElement and
    //an exception is thrown and we end up here. Testing some
    //properties that all elements have (works on IE7)
    return (typeof obj==="object") &&
      (obj.nodeType===1) && (typeof obj.style === "object") &&
      (typeof obj.ownerDocument ==="object");
  }
}

它是DOM Level2的一部分

更新 2:这就是我在自己的库中实现它的方式:(之前的代码在 Chrome 中不起作用,因为 Node 和 HTMLElement 是函数而不是预期的对象。此代码在 FF3、IE7、Chrome 1 和 Opera 中进行了测试9).

//Returns true if it is a DOM node
function isNode(o){
  return (
    typeof Node === "object" ? o instanceof Node : 
    o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName==="string"
  );
}

//Returns true if it is a DOM element    
function isElement(o){
  return (
    typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
    o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
);
}
顺便说一句,HTMLElement总是 a function,所以typeof会让你偏离轨道并执行语句的第二部分。如果您愿意instanceof Object您可以尝试,因为该函数将是 的实例Object,或者只是显式检查typeof === "function",因为NodeHTMLElement都是本机对象函数。
2021-03-26 20:51:44
值得注意的是,这不适用于属于其他窗口/框架的元素。鸭子打字是推荐的方法
2021-03-28 20:51:44
当您调用时isElement(0),它返回 0,而不是 false...为什么会这样,我该如何防止?
2021-03-29 20:51:44
WTF事实:火狐5和早期恢复true[] instanceof HTMLElement
2021-04-01 20:51:44
你可以欺骗它: function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);
2021-04-09 20:51:44

以下IE8兼容,超简单的代码完美运行。

接受的答案没有检测到所有类型的HTML元素。例如,不支持 SVG 元素。相比之下,这个答案既适用于 HTML,也适用于 SVG。

在这里查看它的实际效果:https : //jsfiddle.net/eLuhbu6r/

function isElement(element) {
    return element instanceof Element || element instanceof HTMLDocument;  
}
请注意,这不适用于多个窗口。window.open().document.body instanceof Element返回false
2021-03-22 20:51:44
@nik10110 您正在检查新窗口的body实例是否是旧窗口的Element. 如果您按如下方式调整代码,它会起作用:-)win = window.open(); win.document.body instanceof win.Element; // true
2021-03-22 20:51:44
“元素”在 IE7 上未定义
2021-03-24 20:51:44
我可以理解在某一点上有限制。然而,这种限制的目的是限制安全责任。在这一点上,为了安全起见限制使用 IE7 就像试图在防水布盖板的门上放一个死锁。
2021-04-02 20:51:44
我认为任何仍在使用 IE7 的人都应该花 5 秒钟时间下载更好的浏览器,而不是让我们投入数天或数周的时间来解决他们拒绝与时俱进的问题。
2021-04-06 20:51:44

不需要 hacks,你可以只询问一个元素是否是 DOM Element的实例

const isDOM = el => el instanceof Element
杰出的!作品!
2021-03-31 20:51:44
几乎完全兼容(caniuse.com/mdn-javascript_operators_instanceof),这应该是公认的答案
2021-04-02 20:51:44
旁注:如果任何人也将使用它来检查元素是否仍然是 DOM 的一部分(这有点像这个问题),那么这个检查就会失败。它只检查元素的类型,而不是它的真实存在。
2021-04-02 20:51:44

上面和下面的所有解决方案(包括我的解决方案)都有可能不正确,尤其是在 IE 上——很有可能(重新)定义一些对象/方法/属性来模拟使测试无效的 DOM 节点。

所以通常我使用鸭子类型的测试:我专门针对我使用的东西进行测试。例如,如果我想克隆一个节点,我会像这样测试它:

if(typeof node == "object" && "nodeType" in node &&
   node.nodeType === 1 && node.cloneNode){
  // most probably this is a DOM node, we can clone it safely
  clonedNode = node.cloneNode(false);
}

基本上,它是对我计划使用的方法(或属性)的一点完整性检查 + 直接测试。

顺便说一下,上面的测试是对所有浏览器上的 DOM 节点的一个很好的测试。但是,如果您想安全起见,请始终检查方法和属性的存在并验证它们的类型。

编辑: IE 使用 ActiveX 对象来表示节点,因此它们的属性不会作为真正的 JavaScript 对象,例如:

console.log(typeof node.cloneNode);              // object
console.log(node.cloneNode instanceof Function); // false

而它应该true分别返回“函数”和测试方法的唯一方法是查看是否已定义。

“typeof document.body.cloneNode”确实在我的 IE 中返回“对象”
2021-04-08 20:51:44
这看起来是一个不错的答案。请参阅下面的答案, stackoverflow.com/a/36894871/1204556
2021-04-10 20:51:44

您可以尝试将其附加到真正的 DOM 节点...

function isDom(obj)
{
    var elm = document.createElement('div');
    try
    {
        elm.appendChild(obj);
    }
    catch (e)
    {
        return false;
    }

    return true;
}
+1 表示它提供的创造力和确定性。但是,如果该节点碰巧已经是 DOM 的一部分,那么您只是将其删除了!所以......如果需要的话,如果不做将元素重新添加到 DOM 的工作,这个答案是不完整的。
2021-03-14 20:51:44
或者,而不是试图追加克隆的元素,只是想克隆它应该足够:obj.cloneNode(false)有没有副作用。
2021-03-16 20:51:44
这真的很昂贵,而且不必要地复杂。请参阅下面的答案,stackoverflow.com/a/36894871/1204556
2021-03-26 20:51:44
我在将近 5 年后读到这篇文章,我认为它是最酷的之一。它只需要细化。例如,您可以尝试将节点克隆附加到分离的元素。如果那不是 DOM 对象。肯定会出错。尽管如此,仍然是一个相当昂贵的解决方案。
2021-03-27 20:51:44
这行得通吗?它仍然是一个解决方案。一个有创意的人。
2021-04-08 20:51:44