2

我尝试通过以下代码检查属性 clientHeight:

document.documentElement != null && document.documentElement.hasOwnProperty('clientHeight')

结果是假的,因为 document.documentElement.hasOwnProperty('clientHeight') 但是当我检查它'clientHeight' in document.documentElement时返回真。在 Chrome、FF、Opera 中一切正常。这种行为的原因是什么?

4

1 回答 1

2

没有回答你的问题(这是什么原因),但仍然想分享,所以从评论中扩展:

具有属性的对象并不一定意味着该属性由该对象“拥有”;它可以在原型链中。

检查这一点(在 Chrome DevTools 控制台中):

Object.create({"foo":"bar"}).hasOwnProperty("foo")
false
"foo" in Object.create({"foo":"bar"})
true

如您所见,foo创建的对象中确实存在,但它不是对象“拥有”的,只是位于原型链中。

当谈到 DOM 原型时,事情可能会稍微复杂一些,因为不同的平台可能会以不同的方式实现相同的东西。

根据MDNclientHeight定义在 中Element.prototype,所以

在 Firefox 的控制台中,我得到:

[17:09:55.701] document.documentElement.hasOwnProperty("clientHeight")
[17:09:55.702] false
--
[17:10:19.894] "clientHeight" in document.documentElement
[17:10:19.895] true

但在 Opera Dragonfly 控制台中,我得到了:

>>> document.documentElement.hasOwnProperty("clientHeight")
true
>>> "clientHeight" in document.documentElement
true

在 Chrome DevTools 控制台中,我得到了:

document.documentElement.hasOwnProperty("clientHeight")
true
"clientHeight" in document.documentElement
true

(我现在没有 IE10 可以测试,但如果我没记错的话,IE10 遵循 Firefox 风格)

因此,在 Chrome 和 Opera 中似乎clientHeight是定义为“每个元素”,而不是在Element.prototype. 再往前走一点,你可以看到:

Object.getPrototypeOf(document.documentElement)
HTMLHtmlElement {insertAdjacentHTML: function, insertAdjacentText: function, click: function, insertAdjacentElement: function, getAttribute: function…}
    constructor: function HTMLHtmlElement() { [native code] }
    __proto__: HTMLElement
        click: function click() { [native code] }
        constructor: function HTMLElement() { [native code] }
        insertAdjacentElement: function insertAdjacentElement() { [native code] }
        insertAdjacentHTML: function insertAdjacentHTML() { [native code] }
        insertAdjacentText: function insertAdjacentText() { [native code] }
        __proto__: Element

至于你的问题,我想说,无论你想完成什么,不要依赖这个“标准”,使用特征检测。


当我尝试在 JS 中克隆对象时,我首先注意到了这种行为。

当试图克隆一个ClientRect对象(例如document.body.getBoundingClientRect())时,当我想有点花哨时,我首先尝试:

var cloned={};
if(cloned.__proto__) {
    cloned.__proto__=source.__proto__;
}
for(var i in source) {
    if(Object.prototype.hasOwnProperty.call(source,i)){
        cloned[i]=source[i];
    }
}

在 Chrome 中它工作正常,但在 Firefox 中cloned看起来像{width:undefined,height:undefined...}. 所以我改变了for..in这个:

for(var in source) {
    cloned[i]=source[i];
}

在 Firefox 中,这首先给了我一个异常,i因为这 6 个属性是只读的。

在一些失败之后,我得出结论,ClientRect在 Firefox 中是不可构造的,因此不是严格的,完全可克隆的。

于 2013-05-29T09:36:56.497 回答