Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: JS.Class biblioteka ułatwiająca tworzenie i rozszerzanie obiektów w JSie
Forum PHP.pl > Inne > Oceny
deirathe
http://code.google.com/p/jsclassextend/

Mała biblioteka do tworzenia i rozszerzania obiektów w JSie. Prosta klasa:


  1. var Sample = JS.Class({
  2. test : function () {
  3. }
  4. });



rozszerzanie:
  1. var ExtendedSample = Sample.extend({
  2. test2 : function () {
  3. }
  4. });


instancja:

  1. var obj = new ExtendedSample();


więcej przykładów na googlecodzie, zapraszam do komentów smile.gif
zegarek84
JavaScript jest specyficzny - aby zrozumieć o co mi chodziło przeczytaj także komentarze w przykładowych krótkich kodach

zależy co rozumiesz tutaj przez extend - jeśli to co np. w PHP extends rozszerzanie klas to obiekt przekazywany w metodzie extend nie powinien nadpisywać zmiennych - nadpisywanie powinno być w drugą stronę... nie działa także instanceof...

chyba, że chciałeś w drugą stronę, że dla przykładu cTest.extend(cTest2) - że cTest2 zostanie rozszerzone o cTest - jednak instanceof także nie działa gdy sobie zrobimy obiekt oTest2 = new cTest2; alert(oTest2 instanceof cTest);

dla przykładu tutaj np. zamiast zapisać:
[JAVASCRIPT] pobierz, plaintext
  1. var TestClass = JS.Class({
  2. a: 9,
  3. methodA : function (param) {
  4. //method body
  5. $('#hello').append(param);
  6. }
  7. });
  8. var oTest = new cTest;
  9. var cExtendedTestClass = TestClass.extend(oTest);
[JAVASCRIPT] pobierz, plaintext

można zapisać:
[JAVASCRIPT] pobierz, plaintext
  1. var cExtendedTestClass = JS.Class({
  2. a: 9,
  3. methodA : function (param) {
  4. //method body
  5. $('#hello').append(param);
  6. }
  7. }).extend(oTest);
  8. // lub ...extend(cTest)
  9. // gdzie oTest - obiekt, cTest - klasa - czyli także obiekt, tyle, że to konstruktor i funkcja...
[JAVASCRIPT] pobierz, plaintext


dokładniej o co mi chodzi zawarłem w przykładach
[JAVASCRIPT] pobierz, plaintext
  1. var cTest = function(){
  2. };
  3. cTest.prototype = {
  4. a: 2,
  5. b: 3
  6. };
  7.  
  8. //sample js class
  9. var TestClass = JS.Class({
  10. a: 9,
  11. methodA : function (param) {
  12. //method body
  13. $('#hello').append(param);
  14. }
  15. });
  16. var oTest = new cTest;
  17. var cExtendedTestClass = TestClass.extend(oTest);
  18.  
  19. var oExtendedTestClass = new cExtendedTestClass();
  20.  
  21. // return false, 2, 3, false;
  22. // powinno być: true, 9, 3 ?jaki może ma być inna logika?
  23. alert([oExtendedTestClass instanceof cTest, oExtendedTestClass.a, oExtendedTestClass.b, oTest instanceof cExtendedTestClass]);
  24.  
  25. var cNewClass = function(){};
  26. // extend cTest
  27. cNewClass.prototype = new cTest;
  28. // other methods
  29. cNewClass.prototype.a = 9;
  30. cNewClass.prototype.fCos = function(){};
  31. cNewClass.prototype.fOther = function(){};
  32.  
  33. var oNewClass = new cNewClass;
  34.  
  35. // return true, 9, 3;
  36. // powinno być: true, 9, 3
  37. alert([oNewClass instanceof cTest, oNewClass.a, oNewClass.b]);
[JAVASCRIPT] pobierz, plaintext


[edit]

jeszcze zapomniałem - przyczepiłbym się jeszcze do zmiennych "statycznych" - wiem, że wielu używa tej nazwy do tego typu konstrukcji, ale dla mnie używając tego określenia to co się robi na zmiennych powinno się dziać np. tak jak w PHP, że nie ważne z którego obiektu próbujesz się odwołać - czy to z wnętrza czy z zewnątrz [pomijam protected i public] to we wszystkich obiektach także utworzonych z dziedziczonych klas ta zmienna powinna mieć tą samą wartość... jak dla mnie skoro obiekty są przekazywane przez referencję to do prototypu dodałbym taki obiekt o stałej nazwie i co konstruktora funkcji o tej samej nazwie np. statyczne - czyli w efekcie cTest.statyczne['jakaś zmienna'] - a wewnątrz po stworzeniu obiektu np. this.statyczne['jakaś zmienna']...

ale to tak ogólnikowo piszę tylko ;] - jak to robiłeś, czy w prototypie konstruktora czy inaczej to kodu nie analizowałem...
nie sprawdzałem czy do extend można dać funkcję - no wiadomo, że można gdyż funkcja jest także obiektem, ale miałem na myśli, czy sprawdzasz, że jest to instanceof Function - gdyż jeśli tak to pasuje potraktować ją jako konstruktor lub jeśli rozszerzasz w drugą stronę to zamiast bezpośrednio iterować po funkcji to powinno się po jej prototypie...
deirathe
Dzięki wielkie za tak wyczerpującą opinię. Słowo static to bardziej definicja constansów niż staticów, dlatego cieszę się że zwróciłeś mi na to uwagę. Co do extenda:
http://jsfiddle.net/lunereaper/BbRdB/18/
tu jest przykład jak to działa i jak dziala instanceof, mi zwracał true.

[JAVASCRIPT] pobierz, plaintext
  1. var cTest = function(){
  2. };
  3. cTest.prototype = {
  4. a: 2,
  5. b: 3
  6. };
  7.  
  8. //sample js class
  9. var TestClass = JS.Class({
  10. a: 9,
  11. methodA : function (param) {
  12. //method body
  13. }
  14. });
  15. var oTest = new cTest;
  16.  
  17. var cExtendedTestClass = TestClass.extend(oTest);
  18.  
  19. var oExtendedTestClass = new cExtendedTestClass();
  20. //true, true
  21. console.log([oExtendedTestClass instanceof cExtendedTestClass, oExtendedTestClass instanceof TestClass]);
[JAVASCRIPT] pobierz, plaintext


Co do Twojego przykładu- nie pomyślałem o takim użyciu tej biblioteki, ale taką funkcjonalność na pewno wprowadzę i za to spostrzeżenie jestem niezmiernie wdzięczny. Na razie jednak można rozszerzać klasy w sposób opisany w mini dokumentacji, czyli za pomocą JSON'a. Instanceof nie działa kiedy sprawdzasz go na swojej klasie, ponieważ do prototypu obiektu, który powstanie za pomocą zdefiniowanej klasy nie jest przypisywany prototyp wrzuconego obiektu a prototyp obiektu który rozszerzamy.

No i tak jak wspomniałeś JS jest nietypowy, dlatego też wszystkie atrybuty w klasie będące obiektami powinny być definiowane w "construct", aby uniknąć niemiłych niespodzianek.
zegarek84
rzeczywiście przy takim stosowaniu instanceof działa ;]...

tylko jak wspomniałem logika wydawała się inna ze względu konstrukcji:
[JAVASCRIPT] pobierz, plaintext
  1. JS.Class({
  2. construct : function () {
  3. this.holder = $('#hello');
  4. },
  5. methodA : function ()
  6. {
  7. this.holder.html('method a');
  8. }
  9. }).extend({});
[JAVASCRIPT] pobierz, plaintext

co w wolnym tłumaczeniu dla mnie znaczyło, iż dziedziczę z klasy podanej w parametrze extend - a jeśli nie podana klasa (funkcja) tylko gotowy obiekt to w tym moim tłumaczeniu metody i zmienne znajdujące się w obiekcie przekazanym do Class() powinny mieć pierwszeństwo i nie powinny być nadpisywane przez zmienne z extend (przynajmniej jak to jest np. w PHP) - podczas gdy do obecnego działania bardziej pasuje nazwa w stylu "dodaj/nadpisz metody i zwróć klasę nie dotykając tej którą tworzę/lub mam" - jakby ciutkę inna logika

swoją drogą jeśli chcieć tworzyć nową klasę rozszerzając inną to można by metodę JS.Class zrobić na 2 parametry - gdzie drugi byłby opcjonalny...
JS.Class(oKonstrukcjaKlasy, oObiekt/KlasaPoKtórymDziedziczymy)....

[JAVASCRIPT] pobierz, plaintext
  1. var cKlasa = JS.Class({
  2. construct : function () {
  3. this.holder = $('#hello');
  4. },
  5. methodA : function ()
  6. {
  7. this.holder.html('method a');
  8. }
  9. },
  10. oJakiśObiekt/KonstruktorKlasy);
  11. // lub z jednym parametrem
  12. var cKlasa2 = JS.Class({
  13. construct : function () {
  14. this.holder = $('#hello');
  15. }
  16. });
  17. // w sumie to i jeśli nikt nie poda pierwszego parametru można by zwrócić po prostu anonimową funkcję czyli pustą klasę
  18. var cKlasa2 = JS.Class();
[JAVASCRIPT] pobierz, plaintext


ps.
jeszcze teraz przyszło mi do głowy coś takiego, że można by jeszcze dorobić np. obsługe abstrakcyjnych metod... a można by to zrobić np. w ten deseń, że np. definiujesz zmienną window.abstract = {} (lub tablica [] lub anonimowa funkcja - nie ważne)... dalej jeszcze tą zmienną sobie zbuforujesz gdzie trzeba - ale mając taką zmienną w window można pisać np. {g: abstract} - a potem w konstruktorze lub na extend strawdzasz czy zmienna !== abstract (jeśli będzie false to trzeba wyrzucić jakiś wyjątek informujący o braku implementacji metody o nazwie...)... z kolei klasy abstrakcyjne mógłbyś utworzyć w taki sposób, że w konstruktor daje się funkcję itterująca po własnych metodach i sprawdzającą czy czasem zmienna nie równa się abstract i wyrzucić wyjątek jeśli komuś przyjdzie do głowy tworzenie obiektu z takiej klasy

oczywiście nazwa abstract jest raczej zarezerwowana [czy jak się to zwie...]

pozdro winksmiley.jpg
deirathe
Nie wiem czy patrzyłeś może w kod który tam leży na googl'u. Twój pomysł mi się mega podoba, ale nie mam koncepcji na chwilę obecną jak tego dokonać biggrin.gif tak żeby instanceof działał jak należy smile.gif

[JAVASCRIPT] pobierz, plaintext
  1. var Test = JS.Class({
  2. a : function() {console.log('3');}
  3. });
  4.  
  5. var eTest = Test.extend({
  6. a : function() {console.log('5');}
  7. });
  8.  
  9. var v = new eTest();
  10. v.a();
[JAVASCRIPT] pobierz, plaintext


To to samo co w php
  1. class Test
  2. {
  3. public function a () { echo "3";}
  4. }
  5. class eTest extends Test
  6. {
  7. public function a () { echo "5";}
  8. }
  9.  
  10. $v = new eTest();
  11.  
  12. $v->a();


Cytat(zegarek84 @ 12.01.2011, 01:43:41 ) *
ps.
jeszcze teraz przyszło mi do głowy coś takiego, że można by jeszcze dorobić np. obsługe abstrakcyjnych metod... a można by to zrobić np. w ten deseń, że np. definiujesz zmienną window.abstract = {} (lub tablica [] lub anonimowa funkcja - nie ważne)... dalej jeszcze tą zmienną sobie zbuforujesz gdzie trzeba - ale mając taką zmienną w window można pisać np. {g: abstract} - a potem w konstruktorze lub na extend strawdzasz czy zmienna !== abstract (jeśli będzie false to trzeba wyrzucić jakiś wyjątek informujący o braku implementacji metody o nazwie...)... z kolei klasy abstrakcyjne mógłbyś utworzyć w taki sposób, że w konstruktor daje się funkcję itterująca po własnych metodach i sprawdzającą czy czasem zmienna nie równa się abstract i wyrzucić wyjątek jeśli komuś przyjdzie do głowy tworzenie obiektu z takiej klasy

oczywiście nazwa abstract jest raczej zarezerwowana [czy jak się to zwie...]

pozdro winksmiley.jpg


Abstract będzie dużo łatwiejsze, można to zrobić tak jak ze static'iem:

[JAVASCRIPT] pobierz, plaintext
  1. var Test = JS.Class({
  2. abstract : {
  3. properties : ['propA','propB'],
  4. methods: ['methodA','methodB']
  5. }
  6. });
[JAVASCRIPT] pobierz, plaintext

zegarek84
do samych źródeł nie zaglądałem - trochu nie mam czasu - tylko na przykłady...

Cytat(deirathe @ 12.01.2011, 02:04:38 ) *
...To to samo co w php...

właśnie dlatego się pytałem w którą stronę jest tutaj dziedziczenie gdyż z samej konstrukcji js nie wiedziałem winksmiley.jpg - fakt faktem sam mogłem sprawdzić pisząc coś na wzór:
[JAVASCRIPT] pobierz, plaintext
  1. var TestClass = JS.Class({
  2. construct : function () {
  3. this.iA = 2;
  4. }
  5. });
  6.  
  7. var ExtendedTestClass = TestClass.extend({
  8. construct : function () {
  9. this.iA = 3;
  10. },
  11. fAlert: function(){alert(this.iA);}
  12. });
  13.  
  14. var oTest = new ExtendedTestClass;
  15. oTest.fAlert();
[JAVASCRIPT] pobierz, plaintext

tyle, że jak już wcześniej wspominałem skoro w extend jest szkielet klasy to tutaj ta nazwa jakoś mi nie pasuje...

pozdro... widzę, iż wiesz co gdzie i to dosyć dobrze napisałeś choć jeszcze można to dopracować by nie było niejasności winksmiley.jpg
bendi
To się przyczepie - zamiast wołania apply, możesz zastosować call i nie przekazywać sztucznej tablicy. Co do własności z podkreśleniem to mam mieszane uczucia, ale rozumiem, że to konwencja dostępu prywatnego.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.