我想要:

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

有好的替代品吗?


当前回答

我有一个特殊的方法来做到这一点,在答案中还没有提到。

我的解决方案基于四个测试。如果对象通过了这四个,那么它就是一个元素:

该对象不是空的。 对象有一个叫做“appendChild”的方法。 方法“appendChild”继承自Node类,而不仅仅是一个冒名方法(具有相同名称的用户创建的属性)。 对象类型为Node Type 1 (Element)。从Node类继承方法的对象总是Node,但不一定是element。

问:如何检查给定的属性是否是继承的,而不是冒名顶替的?

答:要判断一个方法是否真正继承自Node,一个简单的测试是首先验证该属性是否具有“对象”或“函数”类型。接下来,将属性转换为字符串,并检查结果是否包含文本“[Native Code]”。如果结果看起来像这样:

function appendChild(){
[Native Code]
}

然后从Node对象继承了该方法。参见https://davidwalsh.name/detect-native-function

最后,把所有的测试放在一起,解决方案是:

function ObjectIsElement(obj) {
    var IsElem = true;
    if (obj == null) {
        IsElem = false;
    } else if (typeof(obj.appendChild) != "object" && typeof(obj.appendChild) != "function") {
        //IE8 and below returns "object" when getting the type of a function, IE9+ returns "function"
        IsElem = false;
    } else if ((obj.appendChild + '').replace(/[\r\n\t\b\f\v\xC2\xA0\x00-\x1F\x7F-\x9F ]/ig, '').search(/\{\[NativeCode]}$/i) == -1) {
        IsElem = false;
    } else if (obj.nodeType != 1) {
        IsElem = false;
    }
    return IsElem;
}

其他回答

一个绝对正确的方法,检查目标是一个真正的html元素 主要代码:

    (function (scope) {
        if (!scope.window) {//May not run in window scope
            return;
        }
        var HTMLElement = window.HTMLElement || window.Element|| function() {};

        var tempDiv = document.createElement("div");
        var isChildOf = function(target, parent) {

            if (!target) {
                return false;
            }
            if (parent == null) {
                parent = document.body;
            }
            if (target === parent) {
                return true;
            }
            var newParent = target.parentNode || target.parentElement;
            if (!newParent) {
                return false;
            }
            return isChildOf(newParent, parent);
        }
        /**
         * The dom helper
         */
        var Dom = {
            /**
             * Detect if target element is child element of parent
             * @param {} target The target html node
             * @param {} parent The the parent to check
             * @returns {} 
             */
            IsChildOf: function (target, parent) {
                return isChildOf(target, parent);
            },
            /**
             * Detect target is html element
             * @param {} target The target to check
             * @returns {} True if target is html node
             */
            IsHtmlElement: function (target) {
                if (!X.Dom.IsHtmlNode(target)) {
                    return false;
                }
                return target.nodeType === 1;
            },
            /**
             * Detect target is html node
             * @param {} target The target to check
             * @returns {} True if target is html node
             */
            IsHtmlNode:function(target) {
                if (target instanceof HTMLElement) {
                    return true;
                }
                if (target != null) {
                    if (isChildOf(target, document.documentElement)) {
                        return true;
                    }
                    try {
                        tempDiv.appendChild(target.cloneNode(false));
                        if (tempDiv.childNodes.length > 0) {
                            tempDiv.innerHTML = "";
                            return true;
                        }
                    } catch (e) {

                    }
                }
                return false;
            }
        };
        X.Dom = Dom;
    })(this);

您可以查看所讨论的对象或节点是否返回字符串类型。

typeof (array).innerHTML === "string" => false
typeof (object).innerHTML === "string" => false
typeof (number).innerHTML === "string" => false
typeof (text).innerHTML === "string" => false

//any DOM element will test as true
typeof (HTML object).innerHTML === "string" => true
typeof (document.createElement('anything')).innerHTML === "string" => true

确保你检查的是一个实际的HTMLEement,而不是一个与HTML Element具有相同属性的对象,唯一的方法是确定它是否继承自Node,因为它不可能在JavaScript中创建一个新的Node()。(除非原生Node函数被覆盖,否则就不走运了)。所以:

function isHTML(obj) { return obj instanceof Node; } console.log( isHTML(test), isHTML(ok), isHTML(p), isHTML(o), isHTML({ constructor: { name: "HTML" } }), isHTML({ __proto__: { __proto__: { __proto__: { __proto__: { constructor: { constructor: { name: "Function" }, name: "Node" } } } } } }), ) <div id=test></div> <blockquote id="ok"></blockquote> <p id=p></p> <br id=o> <!--think of anything else you want--!>

如果你正在使用jQuery,试试这个

$('<div>').is('*') // true
$({tagName: 'a'}).is('*') // false
$({}).is('*') // false
$([]).is('*') // false
$(0).is('*') // false
$(NaN).is('*') // false

在Firefox中,您可以使用Node实例。该节点在DOM1中定义。

但在IE中就没那么容易了。

"instanceof ActiveXObject"只能说明它是一个本机对象。 “typeof document.body。appendChild=='object'"说明它可以是DOM对象,也可以是其他具有相同功能的对象。

如果有任何异常,只能使用DOM函数和catch来确保它是DOM元素。然而,它可能有副作用(例如改变对象内部状态/性能/内存泄漏)