286

我试图得到:

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

有没有好的替代品?

4

36 回答 36

335

这可能很有趣:

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"
);
}
于 2008-12-21T12:10:59.220 回答
91

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

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

在此处查看实际操作:https ://jsfiddle.net/eLuhbu6r/

function isElement(element) {
    return element instanceof Element || element instanceof HTMLDocument;  
}
于 2016-04-27T15:53:25.460 回答
27

不需要 hack,你可以问一个元素是否是 DOM Element的一个实例:

const isDOM = el => el instanceof Element
于 2016-11-28T17:34:09.733 回答
11

上面和下面的所有解决方案(包括我的解决方案)都存在不正确的可能性,尤其是在 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分别返回“函数”和。测试方法的唯一方法是查看是否已定义。

于 2008-12-22T02:40:17.547 回答
9

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

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

    return true;
}
于 2008-12-21T10:15:30.593 回答
8

测试变量是否为 DOM 元素的简单方法(冗长,但更传统的语法:-)

function isDomEntity(entity) {
  if(typeof entity  === 'object' && entity.nodeType !== undefined){
     return true;
  }
  else{
     return false;
  }
}

或者正如HTMLGuy建议的那样(简洁明了的语法):

const isDomEntity = typeof entity === 'object' && entity.nodeType !== undefined
于 2017-06-15T11:37:41.730 回答
7

这是来自可爱的 JavaScript 库MooTools

if (obj.nodeName){
    switch (obj.nodeType){
    case 1: return 'element';
    case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
    }
}
于 2008-12-21T09:52:12.200 回答
7

Lo-Dash的_.isElement怎么样?

$ npm install lodash.iselement

在代码中:

var isElement = require("lodash.iselement");
isElement(document.body);
于 2014-11-24T19:07:22.507 回答
4

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

function isHTMLElement(o) {
    return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}
于 2011-03-02T19:00:48.823 回答
4

使用此处找到的根检测,我们可以确定例如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

于 2013-12-09T17:14:47.980 回答
3
var IsPlainObject = function ( obj ) { return obj instanceof Object && ! ( obj instanceof Function || obj.toString( ) !== '[object Object]' || obj.constructor.name !== 'Object' ); },
    IsDOMObject = function ( obj ) { return obj instanceof EventTarget; },
    IsDOMElement = function ( obj ) { return obj instanceof Node; },
    IsListObject = function ( obj ) { return obj instanceof Array || obj instanceof NodeList; },

// 实际上我更可能不会使用这些内联,但有时最好有这些快捷方式用于设置代码

于 2013-12-22T00:26:12.307 回答
3

这可能会有所帮助:isDOM

//-----------------------------------
// Determines if the @obj parameter is a DOM element
function isDOM (obj) {
    // DOM, Level2
    if ("HTMLElement" in window) {
        return (obj && obj instanceof HTMLElement);
    }
    // Older browsers
    return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);
}

在上面的代码中,我们使用双重否定运算符来获取作为参数传递的对象的布尔值,这样我们确保条件语句中评估的每个表达式都是布尔值,利用Short-Circuit Evaluation,因此函数返回truefalse

于 2014-10-21T22:28:48.073 回答
3

我认为原型设计不是一个很好的解决方案,但也许这是最快的一个:定义这个代码块;

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

比检查你的对象 isDomElement 属性:

if(a.isDomElement){}

我希望这有帮助。

于 2015-11-04T10:43:58.283 回答
2

您可以查看相关对象或节点是否返回字符串类型。

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
于 2012-08-23T16:43:59.727 回答
2

对于使用 Angular 的用户:

angular.isElement

https://docs.angularjs.org/api/ng/function/angular.isElement

于 2014-12-30T12:22:02.727 回答
2

根据mdn

Element是最通用的基类,所有对象都从该基类Document继承。它只有各种元素共有的方法和属性。

我们可以isElement通过原型来实现。这是我的建议:

/**
 * @description detect if obj is an element
 * @param {*} obj
 * @returns {Boolean}
 * @example
 * see below
 */
function isElement(obj) {
  if (typeof obj !== 'object') {
    return false
  }
  let prototypeStr, prototype
  do {
    prototype = Object.getPrototypeOf(obj)
    // to work in iframe
    prototypeStr = Object.prototype.toString.call(prototype)
    // '[object Document]' is used to detect document
    if (
      prototypeStr === '[object Element]' ||
      prototypeStr === '[object Document]'
    ) {
      return true
    }
    obj = prototype
    // null is the terminal of object
  } while (prototype !== null)
  return false
}
console.log(isElement(document)) // true
console.log(isElement(document.documentElement)) // true
console.log(isElement(document.body)) // true
console.log(isElement(document.getElementsByTagName('svg')[0])) // true or false, decided by whether there is svg element
console.log(isElement(document.getElementsByTagName('svg'))) // false
console.log(isElement(document.createDocumentFragment())) // false

于 2018-12-27T14:22:13.630 回答
1

我认为您需要做的是彻底检查一些始终在 dom 元素中的属性,但它们的组合很可能不会在另一个对象中,如下所示:

var isDom = function (inp) {
    return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};
于 2008-12-21T09:53:10.763 回答
1

在 Firefox 中,您可以使用instanceof Node. 这是在DOM1Node中定义的。

但这在 IE 中并不容易。

  1. “instanceof ActiveXObject”只能判断它是本机对象。
  2. "typeof document.body.appendChild=='object'" 告诉它可能是 DOM 对象,但也可以是其他具有相同功能的东西。

您只能通过使用 DOM 函数确保它是 DOM 元素并捕获任何异常。但是,它可能会产生副作用(例如更改对象内部状态/性能/内存泄漏)

于 2008-12-21T15:50:19.373 回答
1

也许这是另一种选择?在 Opera 11、FireFox 6、Internet Explorer 8、Safari 5 和 Google Chrome 16 中测试。

function isDOMNode(v) {
  if ( v===null ) return false;
  if ( typeof v!=='object' ) return false;
  if ( !('nodeName' in v) ) return false; 

  var nn = v.nodeName;
  try {
    // DOM node property nodeName is readonly.
    // Most browsers throws an error...
    v.nodeName = 'is readonly?';
  } catch (e) {
    // ... indicating v is a DOM node ...
    return true;
  }
  // ...but others silently ignore the attempt to set the nodeName.
  if ( v.nodeName===nn ) return true;
  // Property nodeName set (and reset) - v is not a DOM node.
  v.nodeName = nn;

  return false;
}

函数不会被例如这个所愚弄

isDOMNode( {'nodeName':'fake'} ); // returns false
于 2012-01-05T00:34:40.787 回答
1

这就是我想出的:

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 语句中测试它的原因。例如 IE7 失败了,因为(document.createElement("a")).constructorundefined在 IE7 中。

这种方法的问题在于,document.createElement它确实不是最快的功能,如果你用它测试很多元素,它很容易减慢你的应用程序。为了解决这个问题,我决定缓存构造函数。该对象ElementConstructors将 nodeNames 作为键,并将其相应的构造函数作为值。如果构造函数已经被缓存,它会从缓存中使用它,否则它会创建元素,缓存其构造函数以供将来访问,然后对其进行测试。

第三个测试是令人不快的回退。它测试 el 是否为object,是否有一个nodeType属性设置为1,一个字符串为nodeName。这当然不是很可靠,但绝大多数用户甚至不应该退缩到现在。

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

于 2013-02-07T00:38:29.567 回答
1

测试是否obj继承自Node

if (obj instanceof Node){
    // obj is a DOM Object
}

Node 是HTMLElement 和 Text 继承的基本接口。

于 2014-04-28T13:53:00.653 回答
1

这几乎适用于任何浏览器。(这里没有元素和节点的区别)

function dom_element_check(element){
    if (typeof element.nodeType !== 'undefined'){
        return true;
    }
    return false;
}
于 2015-05-30T01:37:34.993 回答
1

将原始 js 对象与 HTMLElement 区分开来

function isDOM (x){
     return /HTML/.test( {}.toString.call(x) );
 }

采用:

isDOM( {a:1} ) // false
isDOM( document.body ) // true

// 或者

Object.defineProperty(Object.prototype, "is",
    {
        value: function (x) {
            return {}.toString.call(this).indexOf(x) >= 0;
        }
    });

采用:

o={}; o.is("HTML") // false o=document.body; o.is("HTML") // true

于 2015-12-28T12:41:51.957 回答
1

这是我的版本。它支持来自 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'
  )
}
于 2021-07-07T03:55:46.410 回答
0

这是一个使用 jQuery 的技巧

var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")

$(obj).html() == undefined // true
$(element).html() == undefined // false

所以把它放在一个函数中:

function isElement(obj){

   return (typeOf obj === 'object' && !($(obj).html() == undefined));

}
于 2013-11-09T14:41:08.573 回答
0

不要重蹈覆辙,但对于符合 ES5 的浏览器,为什么不只是:

function isDOM(e) {
  return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}

不适用于 TextNodes 并且不确定 Shadow DOM 或 DocumentFragments 等,但适用几乎所有 HTML 标签元素。

于 2014-08-14T21:35:06.813 回答
0

一个绝对正确的方法,检查目标是一个真正的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);

在 IE 5 中测试

于 2016-05-06T19:56:46.130 回答
0

我有一种特殊的方法可以做到这一点,但答案中尚未提及。

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

  1. 对象不为空。

  2. 该对象有一个名为“appendChild”的方法。

  3. “appendChild”方法继承自Node类,它不仅仅是一个冒名顶替的方法(用户创建的具有相同名称的属性)。

  4. 该对象属于节点类型 1(元素)。从Node类继承方法的对象总是 Node,但不一定是 Element。

问:我如何检查给定的财产是否是继承的,而不仅仅是冒名顶替者?

A:判断一个方法是否真正继承自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;
}
于 2016-10-15T18:15:28.177 回答
0

每个DOMElement.constructor返回函数 HTML...Element()[Object HTML...Element]所以...

function isDOM(getElem){
    if(getElem===null||typeof getElem==="undefined") return false;
    var c = getElem.constructor.toString();
    var html = c.search("HTML")!==-1;
    var element = c.search("Element")!==-1;
    return html&&element;
}
于 2016-10-18T19:00:49.110 回答
0
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element

这将检查它是否是 jQuery 或 JavaScript DOM 元素

于 2017-02-10T10:46:16.090 回答
0

保证您检查的是实际的 HTML 元素,而不仅仅是与 HTML 元素具有相同属性的对象的唯一方法是确定它是否从 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--!>

于 2020-04-12T12:58:26.350 回答
-1
var isElement = function(e){
    try{
        // if e is an element attached to the DOM, we trace its lineage and use native functions to confirm its pedigree
        var a = [e], t, s, l = 0, h = document.getElementsByTagName('HEAD')[0], ht = document.getElementsByTagName('HTML')[0];
        while(l!=document.body&&l!=h&&l.parentNode) l = a[a.push(l.parentNode)-1];
        t = a[a.length-1];
        s = document.createElement('SCRIPT');   // safe to place anywhere and it won't show up
        while(a.length>1){  // assume the top node is an element for now...
            var p = a.pop(),n = a[a.length-1];
            p.insertBefore(s,n);
        }
        if(s.parentNode)s.parentNode.removeChild(s);
        if(t!=document.body&&t!=h&&t!=ht)
            // the top node is not attached to the document, so we don't have to worry about it resetting any dynamic media
            // test the top node
            document.createElement('DIV').appendChild(t).parentNode.removeChild(t);
        return e;
    }
    catch(e){}
    return null;
}

我在 Firefox、Safari、Chrome、Opera 和 IE9 上对此进行了测试。我找不到破解它的方法。
从理论上讲,它通过在它之前插入一个脚本标记来测试提议元素的每个祖先以及元素本身。
如果它的第一个祖先追溯到一个已知元素,例如<html><head><body>,并且在此过程中没有抛出错误,那么我们就有了一个元素。
如果第一个祖先没有附加到文档,我们创建一个元素并尝试将提议的元素放置在其中,(然后将其从新元素中删除)。
因此,它要么追溯到已知元素,要么成功附加到已知元素,要么失败。
如果它不是元素,则返回元素或 null。

于 2012-03-29T10:47:10.757 回答
-1

检测元素是否属于 HTML DOM 的最简单和跨浏览器的方法如下:

function inHTMLDom(myelement){
    if(myelement.ownerDocument.documentElement.tagName.toLowerCase()=="html"){
        return true;
    }else{
        return false;
    }
}

inHTMLDom(<your element>); // <your element>:element you are interested in checking.

在 IE6、IE7、IE8、IE9、IE10、FF、Chrome、Safari、Opera 中测试。

于 2013-08-15T06:54:09.900 回答
-1

大多数答案使用某种鸭子类型,例如检查对象是否具有nodeType属性。但这还不够,因为非节点也可以具有类似节点的属性。

另一种常见的方法是instanceof,它可能会产生误报,例如 with Object.create(Node),尽管继承了节点属性,但它不是节点。

此外,上述两种方法都调用内部基本方法,这可能会出现问题,例如,如果测试值是代理。

相反,我推荐的是借用一个节点方法并在我们的对象上调用它。浏览器可能会通过查看代理中不可自定义的内部插槽来检查该值是否为节点,因此即使它们也不会干扰我们的检查。

function isNode(value) {
  try {
    Node.prototype.cloneNode.call(value, false);
    return true;
  } catch(err) {
    return false;
  }
}

如果您愿意,也可以使用属性获取器。

function isNode(value) {
  try {
    Object.getOwnPropertyDescriptor(Node.prototype,'nodeType').get.call(value);
    return true;
  } catch(err) {
    return false;
  }
}

同样,如果你想测试一个值是否是一个元素,你可以使用

function isElement(value) {
  try {
    Element.prototype.getAttribute.call(value, '');
    return true;
  } catch(err) {
    return false;
  }
}
function isHTMLElement(value) {
  try {
    HTMLElement.prototype.click.call(value);
    return true;
  } catch(err) {
    return false;
  }
}
于 2016-08-28T22:16:27.183 回答
-1

如果你使用 jQuery,试试这个

$('<div>').is('*') // true
$({tagName: 'a'}).is('*') // false
$({}).is('*') // false
$([]).is('*') // false
$(0).is('*') // false
$(NaN).is('*') // false
于 2020-05-15T03:58:52.747 回答
-1

我使用这个功能:

function isHTMLDOMElement(obj) {
  if (Object.prototype.toString.call(obj).slice(-8) === 'Element]') {
    if (Object.prototype.toString.call(obj).slice(0, 12) === '[object HTML') {
      return true;
    }
    return false;
  }
  return false;
}

https://jsfiddle.net/1qazxsw2/wz7e0fvj/9/

于 2021-04-07T11:00:53.263 回答