创建一个HTMLCollection

19
我试图对 Element.prototype.children 进行补丁,它应该返回一个 HTMLCollection
有一个 window.HTMLCollection
然而,
var h = new HTMLCollection();
//TypeErrror: HTMLCollection is not a constructor

var h = Object.create(HTMLCollection.prototype);
h[0] = div;
h.item(0); 
// Could not convert JavaScript argument

测试Firefox 7和Chrome

除了使用shim技术转换HTMLCollection,还有其他方法可以与它进行交互吗?

如果您能提出解决方案,请在此GitHub问题中提供反馈。


我认为正确的做法是定义自己的自定义 MyHTMLCollection 构造函数,然后使用它来代替不可靠的宿主构造函数 HTMLCollection - Šime Vidas
虽然我无法回答你关于HTMLCollection的具体问题,但通常认为扩展本地DOM对象是不好的做法。请参阅此文章以获取详细解释:http://perfectionkills.com/whats-wrong-with-extending-the-dom/ - skyline3000
@skyline3000 我非常清楚后果。我们需要这样做来生成一个DOM-shim。我们不是用自定义方法扩展DOM(邪恶),而是使用应该按照DOM4规范存在的方法。 - Raynos
4个回答

17

很棒!这是更新和更合适的答案。 - ey dee ey em
那是一个非常实用的解决方案。 - tipograf ieromonah
1
DocumentFragment必须确保其子元素已从先前的父级分离,因此不是HTMLCollection的对应项。 - Abdillah

7
这是我会做的方法:
function MyHTMLCollection( arr ) {
    for ( var i = 0; i < arr.length; i += 1 ) {
        this[i] = arr[i];
    }

    // length is readonly
    Object.defineProperty( this, 'length', {
        get: function () {
            return arr.length;
        }
    });

    // a HTMLCollection is immutable
    Object.freeze( this );
}

MyHTMLCollection.prototype = {
    item: function ( i ) {
        return this[i] != null ? this[i] : null;
    },
    namedItem: function ( name ) {
        for ( var i = 0; i < this.length; i += 1 ) {
            if ( this[i].id === name || this[i].name === name ) {
                return this[i];
            }
        }
        return null;
    }
};

此处的 arr 是一个包含应该在 HTMLCollection 中的所有 DOM 元素的普通数组。

待办事项:

  • 需要先检查参数 arr 是否符合要求:它是一个数组吗?数组中的所有元素都是 DOM 元素吗?

instance[4] = newEl怎么办?length会失败。我认为你需要在每次获取时计算长度才能使其正常工作。 - Raynos
@Raynos,我刚刚更新了我的答案。在构造函数中使用Object.freeze( this ),但我不确定规范对HTML集合的不可变性有何规定。我会检查一下... - Šime Vidas
也就是说,在IE8中,Object.defineProperty只能用于DOM,所以我的dom-shim在IE8中就失效了。我猜我可以让length属性成为一个静态值,然后就忘掉它。 - Raynos
@ŠimeVidas - 请查看规范,集合具有只读长度。 - RobG
@RobG 是的,我将其定义为一个没有 setter 的访问器属性 - 这使它成为只读属性。{ value: arr.length, writable: false } 更加合适,但这也可以工作。 - Šime Vidas
显示剩余2条评论

6
不要期望宿主对象的行为像(ECMAScript)本地对象,它们是完全不同的东西。一些浏览器确实将它们的DOM对象实现为ECMAScript对象,但这并非必需且不应该依赖。请注意,大多数HTML集合都是动态的,很难在本地对象中模拟。

1
它们确实非常难在没有代理的情况下模拟。 - Raynos

2

我知道这是一个比较旧的问题,但我遇到了类似的需求,需要创建一个空的HTMLCollection。我通过创建一个元素,然后使用一个在该元素中不存在的类运行getElementsByClassName()来实现。

document.createElement("div").getElementsByClassName('noClassHere');

这会返回一个空的HTMLCollection对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接