我想要:

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;
  }
}

有好的替代品吗?


当前回答

旧线程,但这里有一个更新的可能性为ie8和ff3.5用户:

function isHTMLElement(o) {
    return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}

其他回答

使用这里发现的根检测,我们可以确定例如alert是否是对象根的成员,那么它很可能是一个窗口:

function isInAnyDOM(o) { 
  return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}

要确定对象是否是当前窗口甚至更简单:

function isInCurrentDOM(o) { 
  return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}

这似乎比开头线程中的try/catch解决方案更便宜。

没有P

这是我想出来的:

var isHTMLElement = (function () {
    if ("HTMLElement" in window) {
        // Voilà. Quick and easy. And reliable.
        return function (el) {return el instanceof HTMLElement;};
    } else if ((document.createElement("a")).constructor) {
        // We can access an element's constructor. So, this is not IE7
        var ElementConstructors = {}, nodeName;
        return function (el) {
            return el && typeof el.nodeName === "string" &&
                 (el instanceof ((nodeName = el.nodeName.toLowerCase()) in ElementConstructors 
                    ? ElementConstructors[nodeName] 
                    : (ElementConstructors[nodeName] = (document.createElement(nodeName)).constructor)))
        }
    } else {
        // Not that reliable, but we don't seem to have another choice. Probably IE7
        return function (el) {
            return typeof el === "object" && el.nodeType === 1 && typeof el.nodeName === "string";
        }
    }
})();

为了提高性能,我创建了一个自调用函数,它只测试浏览器的功能一次,并相应地分配适当的函数。

第一个测试应该可以在大多数现代浏览器中工作,这里已经讨论过了。它只是测试元素是否是HTMLElement的实例。非常简单。

第二个是最有趣的一个。这是它的核心功能:

return el instanceof (document.createElement(el.nodeName)).constructor

它测试el是构造函数的实例还是它假装是实例。为此,我们需要访问元素的构造函数。这就是为什么我们在if-Statement中测试这个。例如,IE7就失败了,因为(document.createElement("a"))。构造函数在IE7中未定义。

The problem with this approach is that document.createElement is really not the fastest function and could easily slow down your application if you're testing a lot of elements with it. To solve this, I decided to cache the constructors. The object ElementConstructors has nodeNames as keys with its corresponding constructors as values. If a constructor is already cached, it uses it from the cache, otherwise it creates the Element, caches its constructor for future access and then tests against it.

第三个考验是令人不快的退路。它测试el是否是一个对象,是否有一个nodeType属性设置为1,是否有一个字符串作为nodeName。当然,这不是很可靠,但绝大多数用户甚至不应该倒退到这么远。

这是我想到的最可靠的方法,同时还能保持尽可能高的性能。

这是我的版本。它支持来自iframe的元素

/**
 * @param {any} value
 * @param {any} view Optional. If the value is from an iframe, provide the iframe content window here.
 * @returns {boolean}
 */
function isHtmlElement(value, view) {
  if (value instanceof HTMLElement) return true
  if (view && value instanceof view.HTMLElement) return true

  return !!(
    value &&
    typeof value === 'object' &&
    value !== null &&
    value.nodeType === 1 &&
    typeof value.nodeName === 'string'
  )
}

我认为原型并不是一个很好的解决方案,但这可能是最快的方法: 定义此代码块;

Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;

然后检查对象的isDomElement属性:

if(a.isDomElement){}

我希望这能有所帮助。

您可以尝试将它附加到一个真正的DOM节点…

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

    return true;
}