Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Dodawanie metod do ciała obiektu``
Forum PHP.pl > Forum > Po stronie przeglądarki > JavaScript
wukkie
Witajcie,

Przy pisaniu skryptu JS natrafiłem na pewien problem związany z rozszerzaniem głównego obiektu Array. Gdy dodam metody w taki sposób

  1.  
  2. Array.prototype.x =function(){return this;}
  3. Array.prototype.z=function(){return this;}
  4.  
  5. x = [1,2,3]
  6.  
  7. for ( var i in x ){
  8. console.log( x[i] );
  9. }
  10. console.log(x.length)
  11.  


Okaże się że tablica x ma aż 3 elementy, natomiast pętla zwróci zarówno 3 elementy jak i te dwie nowe metody. Czy znacie składnie która pozwoliła by dodawać metody do ciała obiektu, możliwe do wywołania, ale nie widoczne w pętli jako kolejne elementy?
AdIoS_Neo
Witam,
do tablicy w JavaScripcie (a właściwie do danych w niej) uzyskujemy dostęp poprzez indek, np.:
[JAVASCRIPT] pobierz, plaintext
  1. var a = [1, "dwa"];
  2. a[0]; // daje -> 1
  3. a[1] // daje -> dwa
[JAVASCRIPT] pobierz, plaintext
W JS tablica jest również obiektem więc jeśli użyjesz pętli for(var i in a){} to uzyskujesz dostęp nie tylko do danych ale także do pól i metod tego obiektu, tak więc nie da się osiągnąć efektu o który pytasz. Jeśli chcesz wypisać wszystkie elementy z tablicy to musisz użyć pętli w takiej postaci:
[JAVASCRIPT] pobierz, plaintext
  1. var a = [1, "dwa"];
  2. for(var i=0;i<a.length;i++) a[i];
[JAVASCRIPT] pobierz, plaintext


Pozdrawiam
konrados
Możesz sprawdzać czy typeof x[i]!='function'

Tu masz o typeof: http://www.adp-gmbh.ch/web/js/operators/typeof.html
wukkie
Jest to oczywiście rozwiązanie, ale zasięg takiej zmiany jest zbyt nieprzewidywalny. Wykorzystanie dowolnego modułu w którym pojawiły by się operacje na elementach tablic były by awaryjne.


Cytat(AdIoS_Neo @ 10.06.2012, 18:59:12 ) *
Witam,
do tablicy w JavaScripcie (a właściwie do danych w niej) uzyskujemy dostęp poprzez indek, np.:
[JAVASCRIPT] pobierz, plaintext
  1. var a = [1, "dwa"];
  2. a[0]; // daje -> 1
  3. a[1] // daje -> dwa
[JAVASCRIPT] pobierz, plaintext
W JS tablica jest również obiektem więc jeśli użyjesz pętli for(var i in a){} to uzyskujesz dostęp nie tylko do danych ale także do pól i metod tego obiektu, tak więc nie da się osiągnąć efektu o który pytasz. Jeśli chcesz wypisać wszystkie elementy z tablicy to musisz użyć pętli w takiej postaci:
[JAVASCRIPT] pobierz, plaintext
  1. var a = [1, "dwa"];
  2. for(var i=0;i<a.length;i++) a[i];
[JAVASCRIPT] pobierz, plaintext


Pozdrawiam

Zgadza się,
natomiast problem pojawia sie w przypadku gdy posiadam tablicę asocjacyjną.
Tj.
  1. x = []
  2. x["a"] = 1


W tym przypadku nie mogę wykorzystać pętli for ( i=0... ).
Owszem dostaję dostęp do metod, ale tylko dodanych przeze mnie. Co ciekawe w przypadku gdy posiadam tylko jedną dodaną funkcję
w postacie
  1. Array.prototype.x = function(){this}

problem nie występuje.
AdIoS_Neo
właśnie ... jest przecież metoda hasOwnProperty(nazwa) która sprawdza czy obiekt ma takie pole lub metodę i zwraca true lub false. jeśli dopisujesz metody do głównego obiektu to wystarczy sprawdzić w pętli czy jest to pole/metoda tego obiektu np.:
[JAVASCRIPT] pobierz, plaintext
  1. for ( var i in x ){
  2. if(x.hasOwnProperty(i))
  3. console.log( x[i] );
  4. }
[JAVASCRIPT] pobierz, plaintext

oczywiście sprawdzenie metody "x" lub "z" które nie są bezpośrednimi metodami obiektu x da wynik false i nie zostaną one wyświetlone. Problem będzie jeśli napiszemy tak:
[JAVASCRIPT] pobierz, plaintext
  1. x.x = function(){ return "tralala";}
[JAVASCRIPT] pobierz, plaintext
wtedy metoda x staje się bezpośrednią metodą obiektu x i sprawdzenie x.hasOwnProperty("x") da wynik true.
wukkie
Tak, to rozwiązanie jest podobne do tego z typeof i wymusza dodawanie tego warunku w każdej pętli która znajduje się w skrypcie. Lecz co w przyadku gdy wykorzystuje kod napisany przez innego użytkownika i nie przewidział takiego zachowania podczas wywoływania pętli for..in ?

Być może takie rozwiązanie nie istnieje, lecz jestem ciekaw, ze względu na to że problem występuje dopiero przy dwóch dodadnych metodach. Prędzej zrezygnuje z rozszerzeania głównych obiektów niż sprawie że każda pętla for..in będzie wymagała modyfikacji. smile.gif

Może macie doświadczenia z takim problemem?
AdIoS_Neo
Inaczej tego nie obejdziesz niestety, tak w ogóle w JavaScript nie ma tablic asocjacyjnych jak wcześniej napisałeś, a pętla powinna Ci wypisać także jedną metodę którą dodałeś, jeśli tego nie robi to jest gdzieś błąd.
kamil4u
Bo w praktyce rzadko się używa prototype do obiektów globalnych( Array, HTMLElement, itd. ) - przynajmniej ja tak robię smile.gif

Używałbym w takim przypadku metody a'la jQuery, czyli tworzenie własnego obiektu i manipulowanie dopiero nim.
Czyli w przykładzie jQuery mamy $(...).operacja(); , a nie operacje bezpośrednio na elementach DOM( HTMLElement.prototype.operacja = .... ).

Kod
var tablica = ....;
mojObiektObslugującyTablice( tablica ).x();
mojObiektObslugującyTablice( tablica ).y();
wukkie
Cytat(AdIoS_Neo @ 10.06.2012, 20:53:58 ) *
Inaczej tego nie obejdziesz niestety, tak w ogóle w JavaScript nie ma tablic asocjacyjnych jak wcześniej napisałeś, a pętla powinna Ci wypisać także jedną metodę którą dodałeś, jeśli tego nie robi to jest gdzieś błąd.

Faktycznie jest jakaś niespójność i nie wiem skąd się bierze.


Przypadek a: localhost - jedna metoda dodana
  1. Array.prototype["f"] = function(){}
  2. var x = [1,2]
  3. for (var i in x) console.log(x[i]);


Rezultat firebug:
0 1
1 2

1,2

Przypadek b: localhost - dwie metody
  1. Array.prototype["f"] = function(){}
  2. Array.prototype["g"] = function(){}
  3. var x = [1,2]
  4. for (var i in x) console.log(x[i]);

Rezultat firebug:

0 1
1 2
test function()

__proto__ []
constructor [undefined]
prototype []

1,2,function()

Przypadek c:
http://jsbin.com/acozus/edit#javascript,html,live
i tu już wszystko jest jak powinno, czyli odrazu metody sie pojawiają jako elementy w pętli.

Na chromie jest podobnie na moim localhoscie. Jakieś pomysły? worriedsmiley.gif

Cytat(kamil4u @ 10.06.2012, 22:50:56 ) *
Bo w praktyce rzadko się używa prototype do obiektów globalnych( Array, HTMLElement, itd. ) - przynajmniej ja tak robię smile.gif

Używałbym w takim przypadku metody a'la jQuery, czyli tworzenie własnego obiektu i manipulowanie dopiero nim.
Czyli w przykładzie jQuery mamy $(...).operacja(); , a nie operacje bezpośrednio na elementach DOM( HTMLElement.prototype.operacja = .... ).

Kod
var tablica = ....;
mojObiektObslugującyTablice( tablica ).x();
mojObiektObslugującyTablice( tablica ).y();


Zgadza się wszystko, jednak naturalnym miejscem dla metod do manipulacji na samej tablicy, dobrze by był to ten obiekt - biorąc pod uwagę że posiada "wiedzę" potrzebną do wykonania takiego zobowiązania. Po prostu było by to gromadzenie jednego rodzaju operacji w jednej "klasie".
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.