2011-10-13 9 views
7

Próbuję pasowana Element.prototype.children który powinien zwrócić HTMLCollectionstworzyć HTMLCollection

Jest window.HTMLCollection

Jednak

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

i

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

test Firefoksa 7 i Chrome

Oprócz przyciemniania HTMLCollection jest jakikolwiek sposób na interakcję z nim?

zapewniają także opinię na temat this github issue czy można zaproponować rozwiązanie

+0

Wierzę, że właściwym sposobem na to jest zdefiniowanie własnego niestandardowego konstruktora 'MyHTMLCollection', a następnie użycie go zamiast konstruktora hosta' HTMLCollection' (który nie jest niezawodny) –

+0

Chociaż nie mogę odpowiedzieć na twoje konkretne pytanie dotyczące HTMLCollection, ogólnie uważa się za złą praktyką rozszerzanie natywnych obiektów DOM (hostowanych). Zobacz ten artykuł, aby uzyskać szczegółowe wyjaśnienie, dlaczego: http://perfectionkills.com/whats-wrong-with-extending-the-dom/ – skyline3000

+0

@ skyline3000 Doskonale zdaję sobie sprawę z konsekwencji. Musimy to zrobić, aby wygenerować DOM-shim. Nie rozszerzamy DOM o niestandardowe metody (zło), ale o metody, które powinny istnieć zgodnie ze specyfikacją DOM4. – Raynos

Odpowiedz

4

Oto jak zrobiłbym to:

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

gdzie arr jest regularnym układzie, który zawiera wszystkie elementy DOM, które powinny być wewnątrz HTMLCollection.

Lista zadań:

  • argument arr powinny być sprawdzone wcześniej: Czy to jest tablica? Czy są wszystkie elementy elementów DOM tej tablicy?
+0

Co z 'instance [4] = newEl'. "długość" nie powiedzie się. Myślę, że musisz wyliczyć długość przy każdym wywołaniu, aby działał. – Raynos

+0

@Raynos Właśnie zaktualizowałem swoją odpowiedź. 'Object.freeze (this)' wewnątrz konstruktora, ale nie jestem pewien, co mówi spec o niezmienności kolekcji HTML. Sprawdzę ... –

+0

również 'Object.defineProperty' działa tylko na DOM w IE8, więc mój dom-shim właśnie zepsuł się w IE8. Sądzę, że mogę uczynić właściwość 'length' wartością statyczną w IE8 i po prostu o tym zapomnieć. – Raynos

4

nie oczekuj obiekty gospodarza zachowywać się jak (ECMAScript) rodzimych obiektów, są one całkowicie różne rzeczy. Niektóre przeglądarki implementują obiekty DOM, takie jak obiekty ECMAScript, ale nie są wymagane i nie należy na nich polegać. Zwróć uwagę, że większość kolekcji HTML jest na żywo, bardzo trudno jest je emulować w natywnym obiekcie.

+1

Są one rzeczywiście niezwykle trudne do naśladowania bez Proxy. – Raynos

0

Wiem, że to pytanie jest starszy, ale natknąłem się na podobną potrzebę stworzenia pustego HTMLCollection i zrobiłem to po prostu tworząc element, a następnie uruchomić getElementsByClassName() przeciwko nim za pomocą klasy, która nie istnieje w elemencie.

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

Powoduje zwrócenie pustego obiektu HTMLCollection.