2010-07-31 15 views
8

Dobra, moja pierwsza próba wyjaśnienia, co robię, zakończyła się nieszczęśliwie. Zasadniczo kopiuję obiekt Object.create() Crockforda, z wyjątkiem zmiennych prywatnych.Pomysł na dziedziczenie z JavaScriptu (część 2)

Jeśli spojrzysz na zaakceptowaną odpowiedź tutaj: How to inherit from a class in javascript?, zobaczysz Object.create jako ostatni wzór, który moim zdaniem lepiej pasuje do prototypowej natury Javascript (obiekty powodują powstawanie obiektów) zamiast naśladować klasyczne dziedziczenie (klasy powodują tworzenie obiektów) .

Jeśli spojrzysz na artykuł w Wikipedii na temat programowania opartego na prototypach (http://en.wikipedia.org/wiki/Prototype-based_programming), możesz zobaczyć więcej o tym, co mam na myśli.

Wadą z Object.create() jest to, że nie ma wsparcia dla prywatnych członków. To, co proponuję:

Function.prototype.from = function(obj) { 
    function F() {this.parent = Object(obj);} 
    F.prototype = obj; 
    var out = new F(); 
    this.apply(out); 
    return out; 
}; 

Następnie należy utworzyć obiekty jako sposób:

// Create an object 
var a = function() { 
    var private_property = 'blue'; 
    this.public_property = 7; 

    this.public_method = function() { 
     alert(this.public_property + ' ' + private_property); 
    } 
}.from(null); // .from() works too, but .from(null) is more revealing 


// Create a new object using 'a' as the prototype 
var b = function() { 
    var private_property = 'red'; 
    this.public_property = 8; 
}.from(a); 


// See the results 
a.public_method(); // Alerts '7 blue' 
b.public_method(); // Alerts '8 blue' - Parent methods use parent private variables 

a.public_method = function() { alert('rabbit'); }; 

a.public_method(); // Alerts 'rabbit' 
b.public_method(); // Alerts 'rabbit' 

b.public_method = function() { alert('dog'); }; 

a.public_method(); // Alerts 'rabbit' 
b.public_method(); // Alerts 'dog' - Parent method is overwritten 

Sposób zrobiłem „z” funkcja jest taka, że ​​gdy obiekt nadrzędny zmienia swoje metody, jeśli ciebie chcesz zapobiec zmianie w instancji podrzędnej, możesz określić:

this.public_method = this.parent.public_method; 

w instancji podrzędnej.

Należy również pamiętać, że obiekty utworzone ex nihilo nie dziedziczą z Object (hasOwnProperty itp.). Musisz jawnie określić to jako .from (Object).

Korzyści z tego wzoru:

  1. pamięci nie jest marnowana na każdej nowej instancji
  2. To przylega do prawda prototypal spadkowego wzór
  3. mieć dostęp do obiektu nadrzędnego przy użyciu tego. rodzic (to .__ proto__ jest specyficzne dla przeglądarki)
  4. Istnieją zmienne prywatne

Jest jedna poważna wada tej metody, którą mogę wymyślić: składnia funkcji() może wprowadzać ludzi w myślenie, że funkcja jest przypisana do zmiennej zamiast do obiektu.

Moje pytanie brzmi, czy są inne wady, których mi brakuje? (Nie ujmuj wad wzoru prototypowego - to subiektywne - ale tylko moje wdrożenie).

+2

Powinieneś przedstawić swój pomysł jako post na blogu. – Corv1nus

+0

Obiekty utworzone za pomocą funkcji "from()" przekazują wartość 'null' faktycznie dziedziczącą z Object. – Pointy

+0

Ups .. moja pierwsza wersja tego postu użyła \ __ proto \ __ zamiast i od (null) nie odziedziczyła po Object. Muszę już iść, ale naprawię to później ... – Nick

Odpowiedz

1

Po pierwsze, jak już wspomniano, podejście Function.prototype jest naprawdę uciążliwe. Dlaczego nie wdrożyć samo jak to:

Object.createChild = function(obj, constructor) { 
    function F() { this.parent = Object(obj); } 
    F.prototype = obj; 
    var out = new F(); 
    if (typeof constructor == 'function') { 
     constructor.apply(out); 
    } 
    return out; 
}; 

Następnie użyj

var a = Object.createChild(null, function() { /*...*/ }); 
var b = Object.createChild(a, function() { /*...*/ }); 

z tych samych wyników jak wyżej. Bonus: Można pominąć constructor argumentu, tak:

var c = Object.createChild(anything); 

Po drugie, nie wiem, czy istnieje jakiekolwiek użycie prawdziwej prototypal dziedziczenia, jak to nazwać. W rzeczywistości jestem pewien, że funkcja konstruktora jest specjalnie dostosowana do obiektu, który ma zostać rozszerzony (a). W ten sposób masz zamiar skończyć nazywając

var x = f.from(a); 
var y = f.from(a); 

z tego samego f - a kombinacji kółko. I tak, oszczędzasz trochę bajtów pamięci w porównaniu z podejściem opartym na klasach, ale szczerze, kogo to obchodzi?

Mimo to całość jest naprawdę dobrym pomysłem w teorii.

+0

Zrobiłeś kilka dobrych punktów. Mogę zgodzić się, że dziedziczenie prototypowe jest czymś, co jest bardziej użyteczne w teorii niż w praktyce (tak naprawdę, nigdy nie potrzebuję dziedziczenia w moich projektach, więc używam tylko wzorca modułu), ale mój pomysł był w zasadzie sposobem na zrobienie prototypu dziedziczenie bardziej przydatne. Otrzymujesz korzyści z prywatnych zmiennych instancji, a także możliwości dziedziczenia bez zbytniego "hakowania" języka (jak wszystkie te biblioteki z pseudo-klasami). – Nick

+0

Osobiście lubię pomysł tworzenia "klas" z obiektów. Twój pomysł jest dobry, z niewielkimi modyfikacjami. Umieść 'constructor' wewnątrz ciała' F' i zwróć 'F'. Jest to trochę podobne do [metody ExtJS 'extend'] (http://www.sencha.com/deploy/dev/docs/?class=Ext&member=extend), które uważam za bardzo użyteczne. – user123444555621

Powiązane problemy