2011-10-13 22 views
7

Estoy tratando de calzar Element.prototype.children que debe devolver un HTMLCollectioncrear un HTMLCollection

Hay una window.HTMLCollection

Sin embargo

var h = new HTMLCollection(); 
//TypeErrror: HTMLCollection is not a constructor 

y

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

Prueba Firefox 7 y Chrome

Aparte de ajustar HTMLCollection, ¿hay alguna forma de interactuar con él?

también proporcionan retroalimentación sobre this github issue si se puede sugerir una solución

+0

Creo que la forma correcta de hacerlo es definir tu propio constructor 'MyHTMLCollection' personalizado y luego usarlo en lugar del constructor del host' HTMLCollection' (que no es confiable) –

+0

Si bien no puedo responder a tu pregunta específica sobre HTMLCollection, generalmente se considera una mala práctica extender objetos DOM (alojados) nativos. Consulte este artículo para obtener una explicación detallada de por qué: http://perfectionkills.com/whats-wrong-with-extending-the-dom/ – skyline3000

+0

@ skyline3000 Soy perfectamente consciente de las consecuencias. Necesitamos hacer esto para generar un DOM-shim. No estamos ampliando el DOM con métodos personalizados (mal) pero con métodos que deberían existir según la especificación DOM4 – Raynos

Respuesta

4

Así es como yo lo haría:

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

donde arr es una matriz regular que contiene todos los elementos DOM que deben estar dentro de la HTMLCollection.

Para hacer la lista:

  • el argumento arr se debe comprobar de antemano: ¿Es una matriz? ¿Todos los elementos de esa matriz son elementos DOM?
+0

¿Qué pasa con 'instancia [4] = newEl'. 'length' fallará. Creo que debes calcular la longitud en cada llamada para que funcione. – Raynos

+0

@Raynos Acabo de actualizar mi respuesta. 'Object.freeze (this)' dentro del constructor, pero no estoy seguro de lo que dice la especificación sobre la inmutabilidad de las colecciones HTML. Comprobaré ... –

+0

también 'Object.defineProperty' solo funciona en el DOM en IE8 así que mi dom-shim acaba de romper en IE8. Supongo que puedo hacer que la propiedad 'length' sea un valor estático en IE8 y simplemente olvidarme de eso. – Raynos

4

No espere que los objetos se comporten como anfitrión (ECMAScript) objetos nativos, son cosas completamente diferentes. Algunos navegadores implementan sus objetos DOM como objetos ECMAScript, pero no es necesario y no se debe confiar en ellos. Tenga en cuenta que la mayoría de las colecciones de HTML son en vivo, es muy difícil emular eso en un objeto nativo.

+1

Son realmente increíblemente difíciles de emular sin un Proxy. – Raynos

0

Sé que esto es una cuestión más viejo, pero me encontré con una necesidad similar para crear un vacío HTMLCollection y lo hice por la simple creación de un elemento y luego corriendo getElementsByClassName() contra el uso de una clase que no existe en el elemento.

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

Esto devuelve un objeto HTMLCollection vacío.