2016-10-31 2 views
0

Ich versuche, mehr über Javascript zu lernen und ein wenig in die Prototyp-Kette zu graben. Ich wollte eine kleine Erweiterung für ein HTMLElement erstellen, als ich auf dieses Problem stieß. Die Art, wie ich verstehe Object.create ist, dass das Objekt, das an es übergeben wird, verwendet wird, um den Kontext für das neue Objekt zu erstellen, und dass die erste Verknüpfung in der Prototypkette des neu erstellten Objekts auf das Objekt verweist Object.create Methode. In diesem Fall schien mir die Methode der Erweiterung, die in der folgenden bar-Methode verwendet wird, der richtige Ansatz zu sein, da dieses neu erstellte Objekt sein HTMLElement als Kontext erhalten würde.Warum wird die Prototypkette anders ausgeführt?

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Document</title> 
</head> 
<body> 
    <span id="test"></span> 

    <script> 
     HTMLElement.prototype.foo = function() { 
     let foo = Object.create(null); 
     foo.parentElement = this; 
     foo.parentElement.appendChild(document.createElement('div')); 
     } 

     HTMLElement.prototype.bar = function() { 
     let fooRenderer = Object.create(this); 
     fooRenderer.appendChild(document.createElement('div')); 
     } 

     document.getElementById('test').foo(); 
     document.getElementById('test').bar(); 
    </script> 
</body> 
</html> 

Was allerdings passiert, ist, dass die foo Methode korrekt durch ein neues div geordnetes Element zu <span id="test"></span> anhängt, aber bar funktioniert nicht.

Wenn ich die Entwickler-Tools in meinem Browser öffnen und versuchen, die Prototyp-Ketten der beiden Objekte zu folgen, die appendChild auf sie aufgerufen haben, sehen sie fast identisch:

foo Object 
    .parentElement <span#test2> 
     .__proto__ HTMLSpanElementPrototype 
      .__proto__ HTMLElementPrototype 
       .__proto__ ElementPrototype 
        .__proto__ NodePrototype 
         .appendChild 
         .__proto__ EventTargetPrototype 
          .__proto__ Object 
           .__proto__ 
            get 
            set 

fooRenderer Object 
    .__proto__ <span#test2> 
     .__proto__ HTMLSpanElementPrototype 
      .__proto__ HTMLElementPrototype 
       .__proto__ ElementPrototype 
        .__proto__ NodePrototype 
         .appendChild 
         .__proto__ EventTargetPrototype 
          .__proto__ Object 
           .__proto__ 
            get 
            set 

ich geschaffen habe eine jsFiddle mit Dieses Beispiel.

Kann mir bitte jemand erklären, warum bar nicht funktioniert? Ist bar in der Tat der richtige Ansatz? Wenn ja, wie sollte es eingerichtet werden, um ordnungsgemäß zu funktionieren?

Vielen Dank im Voraus für jede Hilfe !!!

+1

Obwohl in Ihrer Prototyp-Kette ein 'HTMLSpanElement' vorhanden ist, ist Ihr' fooRenderer'-Objekt nur ein Objekt und kein echter DOM-Knoten. – Bergi

+0

@Bergi Danke, aber ich bin mir nicht sicher, was du sagst. Wollen Sie damit sagen, dass JavaScript die Prototypkette tatsächlich durchläuft und eine Methode 'appendChild' findet, aber nicht ausführen kann, weil es an einem Punkt und nicht an einem DOM-Knoten ausgeführt wird? – peinearydevelopment

+1

Ja, genau (Sie sollten einen Fehler bekommen, der so etwas besagt). Es wird versucht, für ein Objekt aufgerufen zu werden, das die Knotenmethoden erbt, aber nicht als Knoten initialisiert wurde (und auch kein * natives * DOM-Knotenobjekt ist). – Bergi

Antwort

0

Keines dieser Beispiele ist "korrekt". In Prototyp-Methoden sollten Sie nicht versuchen, eine neue Kopie des Objekts, an das Sie bereits angehängt sind, zu instanziieren. Alles, was Sie tun müssen, ist dies:

HTMLElement.prototype.bar = function() { 
    let div = document.createElement('div'); 
    div.innerHTML = 'fooRenderer'; 
    this.appendChild(div); 
} 

Das erste Beispiel funktioniert nur, weil foo.parentElement wird ein gültiges, nativer Htmlelement, nicht ein benutzerdefinierten erstellte Objekt sein.

Siehe this answer für warum Sie nicht "native" Browser-Methoden wie appendChild für benutzerdefinierte Objekte aufrufen können.

+0

Ich sehe, dass meine Frage nicht vollständig fragte, was ich versuchte zu bekommen. Ich verstehe was du sagst. Ich versuche ein Objekt zu erstellen, auf das ich für zukünftige DOM-Manipulationen verweisen kann. In meinem Beispiel würde ich dann entweder 'das zurückgeben;' am Ende oder in der Funktion ein Objekt erstellen und Objekt mit einer Eigenschaft erstellen, die einen Verweis auf den DOM-Knoten behält und das zurückgibt? Danke! – peinearydevelopment

Verwandte Themen