Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [JavaScript] Obiekty
Forum PHP.pl > Forum > Po stronie przeglądarki > JavaScript
zegarek84
tak trochu się zastanawiałem i nie wiem czy są jakieś różnice w wydajności, bądź ważniejsze w sposobie rozwiązywania problemów niuanse... np. w necie większość konstrukcji obiektów wygląda w ten sposób:
[JAVASCRIPT] pobierz, plaintext
  1. java script:
  2. function obiekt($f)
  3. {
  4. var $c=$f||1;
  5. delete($f);
  6. alert($c);
  7. this.bzdura=function(b){$c*=b;};
  8. this.cos=function(){alert($c);};
  9. }
  10. b=new obiekt;
  11. g=new obiekt(4);
  12. b.bzdura(3);
  13. g.bzdura(10);
  14. g.cos();
  15. b.cos();
  16. void(0);
[JAVASCRIPT] pobierz, plaintext

no i właśnie a pro po publicznych metod i publicznych zmiennych odnośnie tego this.cokolwiek - akurat mi się nie wygodnie pisze, jakoś wolę taką konstrukcję bez this.cokolwiek i bez pisania new podczas tworzenia nowego obiektu:
[JAVASCRIPT] pobierz, plaintext
  1. java script:
  2. function obiekt($f)
  3. {
  4. var $c=$f||1;
  5. delete($f);
  6. alert($c);
  7. return {
  8. bzdura:function(b){$c*=b;},
  9. cos:function(){alert($c);}
  10. };
  11. }
  12. b=obiekt();
  13. g=obiekt(4);
  14. b.bzdura(3);
  15. g.bzdura(10);
  16. g.cos();
  17. b.cos();
  18. void(0);
[JAVASCRIPT] pobierz, plaintext

i tu moje pytanie - jak jest poprawniej, czy są jakieś znaczące tutaj różnice??...
może tak przy okazji jakieś linki do trudniejszych artykułów a ciekawszych z niuansami

z góry dziękuje ...

sorki za podbicie ale znalazłem jeden motyw w tym co ja używam a ktoś mógłby uznać to za wadę - brak zdefiniowanego instanceof - więc odrazu rozwiązanie na instance of without new winksmiley.jpg - tu już może spowolnienie lekkie - na pętlę nie chce mi się sprawdzać - choć raczej nie powinno być gdyż jest zwrócona tylko referencja... a jak jest sporo metod publicznych to jednak wolę pisać jak w poście wyżej drugi przykład zamiast dla każdej metody poprzedzać this...

instance of without new (przykład na zdefiniowanie instancji):
Kod
java script:g=function(){};function c(){var ll=22; return {k:function(){return ll;}}};function a(ob,cialo){ob.prototype=cialo;return new ob;};h=a(g,c());alert(h instanceof g);void(0)

ps. aby instancja zosttała zwrócona to funkcja do której przyrównujemy czy istnieje instancja musi być w zasięgu w miejscu gdzie ją sprawdzamy...

dalej szukam jakichś za i przeciw który sposób lepszy - lub niech ktoś napisze, że to jeden h* winksmiley.jpg

lub jeśli ktoś chce pisać new a nie chce co chwila pisać this wewnątrz gdyż woli notację json:
Kod
java script:g=function(){};function c(){var ll=22; return {k:function(){return ll;}}};g.prototype=c();h=new g;alert(h instanceof g);void(0)
pp-layouts
Specjalnie dla Ciebie, wielki test:

[JAVASCRIPT] pobierz, plaintext
  1. function ms() {
  2. var d = new Date();
  3. return d.getTime();
  4. }
  5.  
  6. function benchmark(fn, iterations) {
  7. var time = ms();
  8. for (var i = 0; i < iterations; i++) fn();
  9. return ms() - time;
  10. }
  11.  
  12. function A(x) {
  13. this.y = x;
  14. this.t = function() {
  15. return this.y++;
  16. };
  17. };
  18.  
  19. B = function(x) {
  20. this.y = x;
  21. this.t = function() {
  22. return this.y++;
  23. };
  24. };
  25.  
  26. C = function(x) {
  27. return {
  28. y : x,
  29. t : function() {
  30. return this.y++;
  31. }
  32. };
  33. };
  34.  
  35. D = function(x) { this.y = x; };
  36. D.prototype = {
  37. y : null,
  38. t : function() {
  39. return this.y++;
  40. }
  41. };
  42.  
  43. iterations = 1000000;
  44.  
  45. td = benchmark(function() { d = new D(3); d.t(); }, iterations);
  46. tc = benchmark(function() { c = new C(2); c.t(); }, iterations);
  47. tb = benchmark(function() { b = new B(1); b.t(); }, iterations);
  48. ta = benchmark(function() { a = new A(0); a.t(); }, iterations);
  49.  
  50. alert("Wyniki: " + [ta, tb, tc, td].join(', ') + 'ms');
  51. alert("Sprawdzenie: " + [a.y, b.y, c.y, d.y].join(', '));
[JAVASCRIPT] pobierz, plaintext



Oto wyniki:

Firefox 3.6 beta 5: 5054, 6622, 5887, 2726 ms

Opera 10.10: 2102, 2079, 2925, 1381 ms

Chrome 4.0.249.43: 310, 302, 369, 75 ms

IE 8: 8085, 8315, 10457, 6007 ms

Są to średnie z 3 testów dla wszystkich przeglądarek z wyjątkiem IE, nie chciało mi się tyle czekać.

Zdecydowanym faworytem jest klasa utworzona z prototypu, czyli nasze D. Rozwiązanie z funkcją zwracającą obiekt © nie sprawdza się za dobrze w większości przeglądarek. Rozwiązania z funkcją i nieszczęsnym this-em (A i cool.gif uzyskują podobny średni wynik, z przewagami zależnymi od przeglądarki.

Pewnie za wcześnie na poważne wnioski, ale ten banalny test wykazuje pewną wyższość konstrukcji z prototypem. Test sprawdza specyficzną rzecz - mianowicie szybkość tworzenia, inicjowania i użycia egzemplarza klasy. Innym razem trzeba sprawdzić jak będą kształtowały się profile wydajności w przypadku iteracji samego użycia egzemplarza, bez jego tworzenia. Sytuacja tworzenia egzemplarza w każdej iteracji jest raczej nietypowa - przez co niezbyt miarodajna.

Żeby zakończyć ten odcinek jakimś morałem - wydaje mi się, że ogólny wniosek płynący z tego doświadczenia - 1 ch. smile.gif Są pewne różnice w wydajności, ale generalnie jeśli nie liczymy taktów procka jak w demie na C64 - style klas zostaną chyba w całości w kwestii upodobań danego programisty.

PS, mały update, sprawdziłem jeszcze

[JAVASCRIPT] pobierz, plaintext
  1. E = function(x) { this.y = x; };
  2. E.prototype.y = null;
  3. E.prototype.t = function() {
  4. return this.y++;
  5. }
[JAVASCRIPT] pobierz, plaintext



Uzyskuje nieznacznie gorsze wyniki od D we wszystkich przeglądarkach z wyjątkiem FF, gdzie wychodzi odrobinę szybciej, ale może to być mimo wszystko błąd pomiaru.

Myślę sobie, że silniki JS chyba optymizują jakoś definicje via prototype. Ja więc zostaję przy nich, z ulubionym stylem Class.prototype = JSON. smile.gif

zegarek84
może będzie ciekawa dyskusja winksmiley.jpg... i a pro po mi chodziło o troszku inny sposób tworzenia obiektów, coś ala jak obiekt C ale bez parametru new (i tu czas jest TNC zbliżony a nawet ciutkę szybszy od ta) , poza tym zawsze powinno się używać var gdyż inaczej zmienne lądują do globalnego window lub czasem powodują błędy jeśli w tym window nie były zdefiniowane - no chyba, że się chce przypisać wartość w window - ale wcześniej tam powinny być zdefiniowane...

pobawiłem się tym skryptem by wyciągnąć dodatkowe wnioski...
no nie trzeba było definiować w prototype pustej zmiennej y skoro jest w funkcji - czas też minimalnie szybszy...

jedna zasadnicza uwaga to w niektórych obiektach często się przydają (choć nie zawsze) zmienne prywatne (definiowane wewnątrz funkcji przez var), więc aby mieć dostęp do niektórych rzeczy zależnych od zmiennych prywatnych lub by móc je "ustawiać" to kilka metod prywatnych należało by zdefiniować w funkcji (i tu najszybciej wypada akurat definicja this.metoda/zmienna)...

wniosek - wszystkie publiczne metody korzystające z publicznych zmiennych/metod i tak jest najszybciej zdefiniować przez rozszerzenie konstruktorem prototype (jednak rozszerzając przez prototype nie mamy dostępu do zmiennych/funkcji prywatnych - chyba, że przez metody publiczne)

ps. w językach skryptowych szybszy jest zapis ++i od zapisu i++

ogólnie może jeszcze ktoś ciekawie podsumuje...
i masz niezły komputer ;p (testy zrobiłem z tym na operze 10.10 na suśle i czasy wyszły mniejsze ;p):
[JAVASCRIPT] pobierz, plaintext
  1. function ms() {
  2. var d = new Date();
  3. return d.getTime();
  4. }
  5.  
  6. function benchmark(fn, iterations) {
  7. var time = ms();
  8. for (var i = 0; i < iterations; i++) fn();
  9. return ms() - time;
  10. }
  11.  
  12. function A(x) {
  13. this.y = x;
  14. this.t = function() {
  15. return this.y++;
  16. };
  17. };
  18.  
  19.  
  20. var B = function(x) {
  21. this.y = x;
  22. this.t = function() {
  23. return this.y++;
  24. };
  25. };
  26. B.prototype={c:99};
  27.  
  28. var C = function(x) {
  29. return {
  30. y : x,
  31. t : function() {
  32. return this.y++;
  33. }
  34. };
  35. };
  36.  
  37. var D = function(x) { this.y = x; };
  38. D.prototype = {
  39. y : null,
  40. t : function() {
  41. return this.y++;
  42. }
  43. };
  44.  
  45. var G = function(x) { this.y = x; };
  46. G.prototype = {
  47. t : function() {
  48. return this.y++;
  49. }
  50. };
  51.  
  52. var F = function(x) {var ob=function(){};
  53. ob.prototype={
  54. y : x,
  55. t : function() {
  56. return this.y++;
  57. }
  58. };
  59. return new ob;
  60. };
  61.  
  62. var iterations = 1000000,
  63.  
  64.  
  65. tc = benchmark(function() {var c = new C(2); c.t(); }, iterations),
  66. TNC = benchmark(function() {var nc = C(9); nc.t(); }, iterations),
  67. TNG = benchmark(function() {var ng = new G(9); ng.t(); }, iterations),
  68. TNF = benchmark(function() {var nf = F(11); nf.t(); }, iterations),
  69. tb = benchmark(function() {var b = new B(1); b.t(); }, iterations),
  70. td = benchmark(function() {var d = new D(3); d.t(); }, iterations),
  71. ta = benchmark(function() {var a = new A(0); a.t(); }, iterations);
  72.  
  73. alert("Wyniki: " + [ta, tb, tc, td, TNC, TNG, TNF].join(', ') + 'ms');
  74. /*alert("Sprawdzenie: " + [a.y, b.y, c.y, d.y, nc.y].join(', ')); //teraz nie ma prawa bytu
  75. */
  76. /*
  77. Wyniki: 8516, 8094, 11139, 2888, 8439, 2630, 15315ms
  78. */
[JAVASCRIPT] pobierz, plaintext
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-2025 Invision Power Services, Inc.