我想要:

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

有好的替代品吗?


当前回答

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

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

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

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

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

如果您愿意,还可以使用属性getter。

函数isNode(value) { 尝试{ Object.getOwnPropertyDescriptor (Node.prototype nodeType) .get.call(价值); 返回true; } catch(err) { 返回错误; } }

类似地,如果您想测试一个值是否是一个元素,您可以使用

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

其他回答

Lo-Dash的_.isElement怎么样?

$ npm install lodash.iselement

在代码中:

var isElement = require("lodash.iselement");
isElement(document.body);

这里有一个使用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));

}

对于那些使用Angular的:

angular.isElement

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

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

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

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

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

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

如果您愿意,还可以使用属性getter。

函数isNode(value) { 尝试{ Object.getOwnPropertyDescriptor (Node.prototype nodeType) .get.call(价值); 返回true; } catch(err) { 返回错误; } }

类似地,如果您想测试一个值是否是一个元素,您可以使用

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

使用这里发现的根检测,我们可以确定例如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