JavaScript Programowanie obiektowe jascob

background image

JavaScript.

Programowanie obiektowe

Autor: Stoyan Stefanov

T³umaczenie: Justyna Walkowska

ISBN: 978-83-246-2242-9

Tytu³ orygina³u:

Object-Oriented JavaScript

Format: B5, stron: 336

Poznaj obiektowe mo¿liwoœci JavaScript!

• Jak rozpocz¹æ przygodê z jêzykiem JavaScript?

• Jak rozszerzaæ obiekty wbudowane?

• Jak pracowaæ w œrodowisku przegl¹darki?

JavaScript jest obiektowym, skryptowym jêzykiem programowania. Choæ sw¹ b³yskotliw¹

karierê jêzyk ten rozpocz¹³ ponad dwanaœcie lat temu, swoimi mo¿liwoœciami wci¹¿

potrafi zaskoczyæ nawet doœwiadczonego programistê. Ostatnio – dziêki technologii

AJAX – znów osi¹gn¹³ on sw¹ szczytow¹ formê. Wykorzystuj¹c w odpowiedni sposób

jego w³aœciwoœci, sprawisz, ¿e twój serwis WWW stanie siê bardziej interaktywny

i dynamiczny.
Dziêki tej ksi¹¿ce dowiesz siê, w jaki sposób u¿yæ do swoich celów obiektowych

mo¿liwoœci jêzyka JavaScript. Jednak zanim zapoznasz siê z tymi tematami, autor

w niezwykle przejrzysty sposób przedstawi Ci podstawy tego jêzyka. Zobaczysz, w jaki

sposób dzia³aj¹ funkcje, pêtle oraz model DOM. Ponadto nauczysz siê korzystaæ ze

wzorców projektowych, wyra¿eñ regularnych oraz prototypów. Pomimo zaawansowanej

tematyki poruszanej przez autora tej ksi¹¿ki dziêki przejrzystemu jêzykowi i klarownemu

uk³adowi stanowi ona œwietn¹ lekturê równie¿ dla pocz¹tkuj¹cych programistów.

• Pojêcia zwi¹zane z programowaniem obiektowym

• Typy danych, tablice, pêtle, sterowanie wykonaniem

• Wykorzystanie funkcji

• Domkniêcia

• Obiekty wbudowane

• Zastosowanie konstruktorów

• Tablice asocjacyjne

• U¿ycie prototypów

• Rozszerzanie obiektów wbudowanych

• Dziedziczenie

• Praca w œrodowisku przegl¹darki (modele BOM i DOM)

• Wzorce kodowania i wzorce projektowe

Od podstaw do sprawnego programowania obiektowego!

background image

Spis treci

O autorze

13

O recenzentach

15

Przedmowa

19

Co znajdziesz w tej ksice?

19

Konwencje

20

Rozdzia 1. Wprowadzenie

23

Troch historii

24

Zapowied zmian

25

Teraniejszo

26

Przyszo

26

Programowanie obiektowe

27

Obiekty

27

Klasy

28

Kapsukowanie

28

Agregacja

29

Dziedziczenie

29

Polimorfizm

30

Programowanie obiektowe — podsumowanie

30

Konfiguracja rodowiska rozwijania aplikacji

31

Niezbdne narzdzia

31

Korzystanie z konsoli Firebug

32

Podsumowanie

33

Rozdzia 2. Proste typy danych, tablice, ptle i warunki

35

Zmienne

35

Wielko liter ma znaczenie

36

Operatory

37

background image

Spis

treci

6

Proste typy danych

40

Ustalanie typu danych — operator typeof

41

Liczby

41

Liczby ósemkowe i szesnastkowe

41

Wykadniki potg

42

Nieskoczono

43

NaN

45

acuchy znaków

45

Konwersje acuchów

46

Znaki specjalne

47

Typ boolean

48

Operatory logiczne

49

Priorytety operatorów

51

Leniwe wartociowanie

52

Porównywanie

53

Undefined i null

54

Proste typy danych — podsumowanie

56

Tablice

56

Dodawanie i aktualizacja elementów tablicy

57

Usuwanie elementów

58

Tablice tablic

58

Warunki i ptle

60

Bloki kodu

60

Warunki if

61

Sprawdzanie, czy zmienna istnieje

62

Alternatywna skadnia if

63

Switch

63

Ptle

65

Ptla while

66

Ptla do…while

66

Ptla for

66

Ptla for…in

69

Komentarze

70

Podsumowanie

71

wiczenia

71

Rozdzia 3. Funkcje

73

Czym jest funkcja?

74

Wywoywanie funkcji

74

Parametry

74

Funkcje predefiniowane

76

parseInt()

76

parseFloat()

78

isNaN()

79

isFinite()

79

Encode/Decode URIs

80

eval()

80

Bonus — funkcja alert()

81

background image

Spis treci

7

Zasig zmiennych

81

Funkcje s danymi

83

Funkcje anonimowe

84

Wywoania zwrotne

84

Przykady wywoa zwrotnych

85

Funkcje samowywoujce si

87

Funkcje wewntrzne (prywatne)

87

Funkcje, które zwracaj funkcje

88

Funkcjo, przepisz e si!

89

Domknicia

90

acuch zakresów

91

Zasig leksykalny

91

Przerwanie acucha za pomoc domknicia

93

Domknicie 1.

94

Domknicie 2.

95

Domknicie 3. i jedna definicja

96

Domknicia w ptli

96

Funkcje dostpowe

98

Iterator

99

Podsumowanie

100

wiczenia

100

Rozdzia 4. Obiekty

103

Od tablic do obiektów

103

Elementy, pola, metody

105

Tablice asocjacyjne

105

Dostp do wasnoci obiektu

106

Wywoywanie metod obiektu

107

Modyfikacja pól i metod

108

Warto this

109

Konstruktory

109

Obiekt globalny

110

Pole constructor

112

Operator instanceof

112

Funkcje zwracajce obiekty

113

Przekazywanie obiektów

114

Porównywanie obiektów

114

Obiekty w konsoli Firebug

115

Obiekty wbudowane

117

Object

117

Array

118

Ciekawe metody obiektu Array

120

Function

122

Wasnoci obiektu Function

123

Metody obiektu Function

125

Nowe spojrzenie na obiekt arguments

126

Boolean

127

Number

128

background image

Spis

treci

8

String

130

Ciekawe metody obiektu String

132

Math

135

Date

136

Metody dziaajce na obiektach Date

138

RegExp

140

Pola obiektów RegExp

141

Metody obiektów RegExp

142

Metody obiektu String, których parametrami mog by wyra enia regularne

143

search() i match()

143

replace()

144

Wywoania zwrotne replace

145

split()

146

Przekazanie zwykego tekstu zamiast wyra enia regularnego

146

Obsuga bdów za pomoc obiektów Error

146

Podsumowanie

150

wiczenia

151

Rozdzia 5. Prototypy

155

Pole prototype

155

Dodawanie pól i metod przy u yciu prototypu

156

Korzystanie z pól i metod obiektu prototype

157

Wasne pola obiektu a pola prototypu

158

Nadpisywanie pól prototypu wasnymi polami obiektu

159

Pobieranie listy pól

160

isPrototypeOf()

162

Ukryte powizanie __proto__

163

Rozszerzanie obiektów wbudowanych

165

Rozszerzanie obiektów wbudowanych — kontrowersje

166

Puapki zwizane z prototypami

167

Podsumowanie

169

wiczenia

170

Rozdzia 6. Dziedziczenie

171

a cuchy prototypów

172

Przykadowy acuch prototypów

172

Przenoszenie wspólnych pól do prototypu

175

Dziedziczenie samego prototypu

177

Konstruktor tymczasowy — new F()

178

Uber: dostp do obiektu-rodzica

180

Zamknicie dziedziczenia wewntrz funkcji

181

Kopiowanie pól

182

Uwaga na kopiowanie przez referencj!

184

Obiekty dziedzicz z obiektów

186

Gbokie kopiowanie

187

object()

189

Poczenie dziedziczenia prototypowego z kopiowaniem pól

190

background image

Spis treci

9

Dziedziczenie wielokrotne

191

Miksiny

193

Dziedziczenie pasoytnicze

193

Wypoyczanie konstruktora

194

Po ycz konstruktor i skopiuj jego prototyp

196

Podsumowanie

197

Studium przypadku: rysujemy ksztaty

200

Analiza

200

Implementacja

201

Testowanie

204

wiczenia

205

Rozdzia 7. rodowisko przegldarki

207

czenie JavaScriptu z kodem HTML

207

BOM i DOM — przegld

208

BOM

209

Ponownie odkrywamy obiekt window

209

window.navigator

210

Firebug jako ciga

210

window.location

211

window.history

212

window.frames

213

window.screen

214

window.open() i window.close()

215

window.moveTo(), window.resizeTo()

216

window.alert(), window.prompt(), window.confirm()

216

window.setTimeout(), window.setInterval()

217

window.document

219

DOM

219

Core DOM i HTML DOM

221

Dostp do wzów DOM

222

Wze document

223

documentElement

224

Wzy-dzieci

224

Atrybuty

225

Dostp do zawartoci znacznika

226

Uproszczone metody dostpowe DOM

227

Rówienicy, body, pierwsze i ostatnie dziecko

228

Spacer przez wzy DOM

230

Modyfikacja wzów DOM

230

Modyfikacja stylu

231

Zabawa formularzami

232

Tworzenie nowych wzów

233

Metoda w peni zgodna z DOM

234

cloneNode()

235

insertBefore()

236

Usuwanie wzów

236

background image

Spis

treci

10

Obiekty DOM istniejce tylko w HTML

238

Starsze sposoby dostpu do dokumentu

239

document.write()

240

Pola cookies, title, referrer i domain

240

Zdarzenia

242

Kod obsugi zdarze wpleciony w atrybuty HTML

242

Pola elementów

242

Obserwatorzy zdarze DOM

243

Przechwytywanie i bbelkowanie

244

Zatrzymanie propagacji

246

Anulowanie zachowania domylnego

248

Obsuga zdarze w ró nych przegldarkach

248

Typy zdarze

249

XMLHttpRequest

250

Wysanie dania

251

Przetworzenie odpowiedzi

252

Tworzenie obiektów XHR w IE w wersjach starszych ni 7

253

A jak asynchroniczny

254

X jak XML

254

Przykad

254

Podsumowanie

257

wiczenia

258

Rozdzia 8. Wzorce kodowania i wzorce projektowe

261

Wzorce kodowania

262

Izolowanie zachowania

262

Warstwa treci

262

Warstwa prezentacji

263

Zachowanie

263

Przykad wydzielenia warstwy zachowania

263

Przestrzenie nazw

264

Obiekt w roli przestrzeni nazw

264

Konstruktory w przestrzeniach nazw

265

Metoda namespace()

266

Rozgazianie kodu w czasie inicjalizacji

267

Leniwe definicje

268

Obiekt konfiguracyjny

269

Prywatne pola i metody

270

Metody uprzywilejowane

271

Funkcje prywatne w roli metod publicznych

272

Funkcje samowywoujce si

273

acuchowanie

273

JSON

274

Wzorce projektowe

275

Singleton

276

Singleton 2

276

Zmienna globalna

277

Pole konstruktora

277

Pole prywatne

278

background image

Spis treci

11

Fabryka

278

Dekorator

280

Dekorowanie choinki

280

Obserwator

282

Podsumowanie

285

Dodatek A Sowa zarezerwowane

287

Lista sów zarezerwowanych majcych specjalne znaczenie w jzyku JavaScript

287

Lista sów zarezerwowanych na uytek przyszych implementacji

288

Dodatek B Funkcje wbudowane

291

Dodatek C Obiekty wbudowane

295

Object

295

Skadowe konstruktora Object

296

Skadowe obiektów tworzonych przez konstruktor Object

296

Array

298

Skadowe obiektów Array

298

Function

301

Skadowe obiektów Function

301

Boolean

302

Number

302

Skadowe konstruktora Number

303

Skadowe obiektów Number

304

String

304

Skadowe konstruktora String

305

Skadowe obiektów String

305

Date

308

Skadowe konstruktora Date

308

Skadowe obiektów Date

309

Math

311

Skadowe obiektu Math

312

RegExp

313

Skadowe obiektów RegExp

314

Obiekty Error

315

Skadowe obiektów Error

315

Dodatek D Wyraenia regularne

317

Skorowidz

323

background image

3

Funkcje

Opanowanie funkcji ma kluczowe znaczenie podczas nauki kadego jzyka programowania,
a w przypadku JavaScriptu jest jeszcze waniejsze ni zwykle. Jest tak dlatego, e w tym j-
zyku funkcje maj bardzo wiele zastosowa i w duej mierze to dziki nim JavaScript jest tak
elastyczny i ekspresywny. W miejscach, gdzie w innych jzykach programowania trzeba by
byo stosowa specjaln skadni w celu wykorzystania obiektowoci, JavaScript udostpnia
funkcje. Ten rozdzia omawia:

Q

definiowanie funkcji i korzystanie z nich,

Q

przekazywanie funkcjom parametrów,

Q

funkcje predefiniowane dostpne za darmo,

Q

zasig zmiennych,

Q

podejcie, zgodnie z którym funkcje to tylko dane specjalnego typu.

Zrozumienie powyszych tematów da nam solidne oparcie przed przejciem do kolejnej cz-
ci rozdziau, w której przedstawione zostan pewne ciekawe zastosowania funkcji:

Q

funkcje anonimowe;

Q

wywoania zwrotne;

Q

samowywoujce si funkcje;

Q

funkcje wewntrzne (zdefiniowane wewntrz innych funkcji);

Q

funkcje, które zwracaj inne funkcje;

Q

funkcje, które zmieniaj swoj definicj;

Q

domknicia.

background image

JavaScript. Programowanie obiektowe

74

Czym jest funkcja?

Funkcje pozwalaj zgrupowa pewn ilo kodu, nada jej nazw, a nastpnie ponownie wy-
korzysta przy uyciu tej wanie nazwy. Spójrzmy na przykad:

function sum(a, b) {
var c = a + b;
return c;
}

Z jakich czci skada si funkcja?

Q

Sowo kluczowe

function

.

Q

Nazwa funkcji, w przykadzie jest to

sum

.

Q

Oczekiwane parametry (argumenty), w tym wypadku

a

i

b

. Funkcja moe mie ich

zero lub wicej. Jeli jest ich wicej ni jeden, parametry rozdziela si przecinkami.

Q

Blok kodu, nazywany ciaem funkcji.

Q

Instrukcja

return

, która umoliwia zwrócenie obliczonej wartoci funkcji. Funkcja

zawsze zwraca warto. Jeli nie robi tego w sposób jawny, niejawnie zwraca
warto

undefined

.

Zwró uwag, e funkcja moe zwróci tylko jedn warto. Jeli potrzebne jest zwrócenie
wikszej liczby wartoci, naley umieci je w tablicy i zwróci tablic jako warto funkcji.

Wywoywanie funkcji

Aby skorzysta z funkcji, naley j wywoa. Funkcj wywouje si poprzez podanie jej nazwy
i argumentów umieszczonych w nawiasie.

Wywoajmy zatem funkcj

sum()

, przekazujc jej dwa argumenty i przypisujc zwracan

przez ni warto zmiennej

result

.

>>> var result = sum(1, 2);
>>> result;

3

Parametry

Podczas definiowania funkcji mona okreli oczekiwane parametry. Funkcja nie musi pobie-
ra parametrów, ale jeli oczekuje, e je otrzyma, a programista podczas wywoywania funkcji
zapomni o ich podaniu, JavaScript przypisze im warto

undefined

. W poniszym przykadzie

funkcja zwraca warto

NaN

, poniewa próbuje doda

1

do

undefined

:

background image

Rozdzia 3. • Funkcje

75

>>> sum(1)

NaN

JavaScript nie wybrzydza podczas pobierania parametrów. Jeli otrzyma ich wicej, ni jest
potrzebne, dodatkowe parametry zostan zignorowane:

>>> sum(1, 2, 3, 4, 5)

3

Na dodatek moliwe jest pisanie funkcji, które mog przyjmowa rón liczb parametrów. Jest to
moliwe dziki tablicy

arguments

, która jest automatycznie tworzona wewntrz kadej funkcji.

Oto funkcja, której dziaanie polega na zwracaniu wszystkich przekazanych jej argumentów:

>>> function args() { return arguments; }
>>> args();

[]

>>> args( 1, 2, 3, 4, true, 'ninja');

[1, 2, 3, 4, true, "ninja"]

Tablica

arguments

pozwoli nam poprawi funkcj

sum()

tak, by przyjmowaa ona dowoln

liczb parametrów i dodawaa je wszystkie.

function sumaNaSterydach() {
var i, res = 0;
var liczba_parametrow = arguments.length;
for (i = 0; i < liczba_parametrow; i++) {
res += arguments[i];
}
return res;
}

Jeli podczas testowania wywoasz t funkcj z inn ni wczeniej liczb parametrów (lub nawet
bez parametrów), zobaczysz, e dziaa tak, jak powinna:

>>> sumaNaSterydach(1, 1, 1);

3

>>> sumaNaSterydach(1, 2, 3, 4);

10

>>> sumaNaSterydach(1, 2, 3, 4, 4, 3, 2, 1);

20

>>> sumaNaSterydach(5);

5

background image

JavaScript. Programowanie obiektowe

76

>>> sumaNaSterydach();

0

Wyraenie

arguments.length

zwraca liczb parametrów podanych podczas wywoania funkcji.

Jeli nie rozumiesz jego skadni, nie przejmuj si, wrócimy do tego w nastpnym rozdziale.
Wtedy take dowiesz si, e

arguments

w rzeczywistoci nie jest tablic, ale obiektem tablico-

podobnym.

Funkcje predefiniowane

Istnieje pewna liczba funkcji, które zostay wbudowane w silnik JavaScriptu i z których mo-
na korzysta do woli. Przyjrzyjmy si im. Warto poeksperymentowa z tymi funkcjami i przyj-
rze si ich argumentom i wartociom zwracanym, by móc pó niej korzysta z nich w wygodny
sposób. Oto lista funkcji wbudowanych:

Q

parseInt()

Q

parseFloat()

Q

isNaN()

Q

isFinite()

Q

encodeURI()

Q

decodeURI()

Q

encodeURIComponent()

Q

decodeURIComponent()

Q

eval()

Zasada czarnej skrzynki

Z reguy podczas korzystania z funkcji Twój program nie musi wiedzie, jakie czynnoci s wykonywane
wewntrz danej funkcji. Moesz myle o funkcjach jako o czarnych skrzynkach — podajesz im pewne
wartoci (w postaci parametrów wejciowych) i odbierasz od nich zwracane wyniki. Jest to prawdziwe
dla wszystkich funkcji — tych wbudowanych w jzyk JavaScript, tych pisanych przez Ciebie oraz tych
stworzonych przez Twoich wspópracowników lub nieznanych Ci programistów.

parseInt()

parseInt()

pobiera argument dowolnego typu (najczciej acuch znaków) i próbuje zamie-

ni go na liczb cakowit. Jeli operacja si nie powiedzie, zwrócona zostanie warto

NaN

.

>>> parseInt('123')

123

background image

Rozdzia 3. • Funkcje

77

>>> parseInt('abc123')

NaN

>>> parseInt('1abc23')

1

>>> parseInt('123abc')

123

Funkcja pobiera jeszcze opcjonalny drugi argument, który okrela podstaw, opisujc typ
liczby: dziesitny, szesnastkowy, binarny itp. Przykadowo: nie ma sensu próba zamiany po-
brania liczby dziesitnej z acucha

"FF"

, zatem wynikiem bdzie NaN, jednak jeli potrak-

tujemy

"FF"

jako liczb szesnastkow, otrzymamy wynik 255.

>>> parseInt('FF', 10)

NaN

>>> parseInt('FF', 16)

255

Spróbujmy teraz sparsowa liczby o rónych podstawach:

10

(liczba dziesitna) i

8

(liczba

ósemkowa).

>>> parseInt('0377', 10)

377

>>> parseInt('0377', 8)

255

Jeli drugi argument nie zostanie podany, za podstaw uznawana jest liczba

10

, z nastpuj-

cymi wyjtkami:

Q

Jeli jako pierwszy argument przekazany zostanie acuch zaczynajcy si od

0x

,

drugiemu argumentowi (jeli nie zosta podany) przypisana zostanie warto

16

(liczba zostanie uznana za szesnastkow).

Q

Jeli pierwszy parametr zaczyna si od

0

, drugi otrzyma warto

8

.

>>> parseInt('377')

377

>>> parseInt('0377')

255

>>> parseInt('0x377')

887

background image

JavaScript. Programowanie obiektowe

78

Najbezpieczniejszym rozwizaniem jest okrelanie podstawy za kadym razem. Jeli tego nie
zrobisz, kod prawdopodobnie zadziaa w 99% przypadków (poniewa najczciej parsuje si
liczby dziesitne), jednak jeli trafisz na liczb zapisan w innym systemie, moesz osiwie,
zanim uda Ci si znale  przyczyn bdu. Wyobra sobie na przykad, e parsujesz pola for-
mularza, który reprezentuje kalendarz, i e uytkownik wpisa

08

, majc na myli sierpie.

Jeli nie podasz podstawy, otrzymasz wynik inny ni oczekiwany.

parseFloat()

parseFloat()

dziaa podobnie do

parseInt(),

ale oczekuje uamków. Pobiera ona tylko jeden

parametr.

>>> parseFloat('123')

123

>>> parseFloat('1.23')

1.23

>>> parseFloat('1.23abc.00')

1.23

>>> parseFloat('a.bc1.23')

NaN

Podobnie jak

parseInt()

,

parseFloat()

podda si po napotkaniu pierwszego znaku, z którym

nie bdzie umiaa sobie poradzi, nawet jeli pozostaa cz tekstu zawiera poprawne liczby.

>>> parseFloat('a123.34')

NaN

>>> parseFloat('a123.34')

NaN

>>> parseFloat('12a3.34')

12

parseFloat()

, w przeciwiestwie do

parseInt()

, jest w stanie poprawnie zinterpretowa zapis

wykadniczy.

>>> parseFloat('123e-2')

1.23

>>> parseFloat('123e2')

12300

background image

Rozdzia 3. • Funkcje

79

>>> parseInt('1e10')

1

isNaN()

Przy pomocy

isNaN()

mona sprawdzi, czy warto wejciowa jest liczb, której mona bez-

piecznie uywa w operacjach arytmetycznych.

isNaN()

pozwala w wygodny sposób dowie-

dzie si, czy funkcjom

parseInt()

i

parseFloat()

udao si sparsowa liczb.

>>> isNaN(NaN)

true

>>> isNaN(123)

false

>>> isNaN(1.23)

false

>>> isNaN(parseInt('abc123'))

true

Ta funkcja take stara si zamieni parametr wejciowy na liczb:

>>> isNaN('1.23')

false

>>> isNaN('a1.23')

true

Funkcja

isNaN()

jest potrzebna take dlatego, e liczba

NaN

nie jest równa samej sobie. Wyni-

kiem porównania

NaN === NaN

bdzie false!

isFinite()

Funkcja

isFinite()

sprawdza, czy warto parametru wejciowego to liczba róna od

Infinity

i róna od

NaN

.

>>> isFinite(Infinity)

false

>>> isFinite(-Infinity)

false

background image

JavaScript. Programowanie obiektowe

80

>>> isFinite(12)

true

>>> isFinite(1e308)

true

>>> isFinite(1e309)

false

Jeli dziwi Ci dwa ostatnie wyniki, przypominam, e zgodnie z tym, co napisaem w poprzed-
nim rozdziale, najwiksz dopuszczaln liczb w jzyku JavaScript jest

1.7976931348623157e+308

.

Encode/Decode URIs

W adresach URL (Uniform Resource Locator) i URI (Uniform Resource Identifier) niektóre znaki
maj specjalne znaczenie. Jeli chcemy mie pewno, e zostan one zapisane poprawnie
(czyli jeli chcemy zastosowa sekwencj uniku), moemy skorzysta z funkcji

encodeURI()

lub

encodeURIComponent()

. Pierwsza z nich zwróci poprawny adres URL, druga zaoy, e przeka-

zany jej parametr jest tylko czci URL (na przykad zawiera parametry dania), i odpo-
wiednio zakoduje wszystkie nietypowe znaki.

>>> var url = 'http://www.packtpub.com/scr ipt.php?q=this and that';
>>> encodeURI(url);

"http://www.packtpub.com/scr%20ipt.php?q=this%20and%20that"

>>> encodeURIComponent(url);

"http%3A%2F%2Fwww.packtpub.com%2Fscr%20ipt.php%3Fq%3Dthis%
20and%20that"

Dziaanie przeciwne do

encodeURI()

i

encodeURIComponent()

maj funkcje

decodeURI()

i

decode

´URIComponent()

. W starszym kodzie mona natkn si na starsze funkcje

escape()

i

unescape()

,

jednak s one przestarzae i nie naley ich stosowa.

eval()

Funkcja

eval()

pobiera acuch znaków i uruchamia go jako kod w jzyku JavaScript:

>>> eval('var ii = 2;')
>>> ii

2

eval('var ii = 2;')

dziaa dokadnie tak samo jako

var ii = 2;

background image

Rozdzia 3. • Funkcje

81

S sytuacje, w których

eval()

si przydaje, jednak w miar moliwoci naley tej funkcji uni-

ka. Z reguy mona zastosowa inne rozwizania, które w wikszoci przypadków s bardziej
eleganckie i atwiejsze w utrzymaniu. Weterani JavaScriptu jak mantr powtarzaj zdanie

eval

is evil” („

eval

to samo zo”). Mona wymieni nastpujce wady tej funkcji:

Q

Wydajno: wykonywanie kodu „na ywo” jest wolniejsze od wykonywania kodu
zapisanego w skrypcie.

Q

Bezpieczestwo: JavaScript ma due moliwoci, co oznacza, e przy jego
„pomocy” mona co zepsu. Jeli nie moesz ufa ródu, z którego pochodzi
wejcie przekazywane do

eval()

, nie wywouj tej funkcji.

Bonus — funkcja alert()

Spójrzmy jeszcze na bardzo popularn funkcj

alert()

. Nie naley ona do rdzenia jzyka (nie

ma jej w specyfikacji ECMA), ale mona z niej korzysta w rodowisku przegldarki. Pozwala
ona na wywietlanie komunikatów w okienku dialogowym. Czasami przydaje si to podczas
testowania i debugowania aplikacji, chocia w tym celu lepiej korzysta z debugera Firebug.
Na poniszym rysunku wida efekt wykonania kodu

alert("halo!")

.

Pamitaj tylko, e okienko dialogowe blokuje wtek przegldarki, co oznacza, e aden inny
kod nie zostanie wykonany, zanim uytkownik nie kliknie OK. Jeli aplikacja jest czsto aktu-
alizowan aplikacj AJAX, to

alert()

nie jest najlepszym pomysem.

Zasig zmiennych

Warto zwróci uwag, zwaszcza, jeli jest si osob, która wczeniej programowaa w innym
jzyku, e zmienne w jzyku JavaScript nie s definiowane w obrbie bloku, tylko funkcji.
Oznacza to, e jeli zmienna zostaa zdefiniowana wewntrz funkcji, nie jest widoczna poza
ni. Natomiast zmienna zdefiniowana wewntrz bloku

if

lub

for

jest widoczna poza blokiem.

Zmienne globalne to zmienne uywane poza funkcjami, natomiast zmienne lokalne to zmienne
uywane wewntrz funkcji. Kod wewntrz funkcji ma dostp zarówno do zmiennych global-
nych, jak i do swoich zmiennych lokalnych.

background image

JavaScript. Programowanie obiektowe

82

W poniszym przykadzie:

Q

funkcja

f()

ma dostp do zmiennej

global

,

Q

poza funkcj

f()

zmienna

local

nie istnieje.

var global = 1;
function f() {
var local = 2;
global++;
return global;
}
>>> f();

2

>>> f();

3

>>> local

local is not defined

Ponadto naley mie na uwadze, e jeli do deklaracji zmiennej nie zostanie uyta instrukcja

var

, zmienna bdzie miaa zasig globalny. Spójrzmy na przykad:

Co si stao? Funkcja

f()

zawiera zmienn

local

. Przed wywoaniem funkcji zmienna nie ist-

nieje. Jednak podczas pierwszego wywoania funkcji zmienna jest tworzona i ma zasig glo-
balny. Dlatego jeli wówczas spróbujemy sign do zmiennej

local

, okae si ona dostpna.

Dobre rady



Staraj si ogranicza liczb zmiennych globalnych. Wyobra sobie dwie osoby pracujce nad dwiema
rónymi funkcjami w tym samym skrypcie, które przypadkowo postanawiaj nada t sam nazw
zmiennej globalnej. Moe to doprowadzi do nieoczekiwanych wyników i trudnych do wykrycia bdów.



Zawsze deklaruj zmienne za pomoc instrukcji var.

background image

Rozdzia 3. • Funkcje

83

Poniszy przykad ilustruje wany aspekt podziau na zmienne lokalne i globalne.

var a = 123;
function f() {
alert(a);
var a = 1;
alert(a);
}
f();

By moe spodziewasz si, e pierwszy

alert()

wywietli

123

(warto globalnej zmiennej

a

),

a drugi wywietli

1

(warto lokalnej zmiennej

a

). Jednak stanie si inaczej. Pierwszy

alert()

pokae

"undefined"

. Stanie si tak dlatego, e wewntrz funkcji zasig lokalny jest waniejszy

od globalnego. Zmienna lokalna nadpisuje zmienn globaln o tej samej nazwie. Podczas wy-
konywania pierwszego

alert()

,

a

nie byo jeszcze zdefiniowane (std warto

undefined

), ale

ju istniao w lokalnej przestrzeni nazw.

Funkcje s danymi

Zrozumienie tego punktu widzenia bdzie na pó niejszym etapie bardzo wane — funkcje
tak naprawd s danymi. Oznacza to, e nastpujce dwie metody definiowania funkcji s
równowane:

function f(){return 1;}
var f = function(){return 1;}

Drugi z pokazanych sposobów definiowania funkcji okrela si mianem zapisu literaowego
funkcji
. Jeli na zmiennej, której zostaa przypisana warto bdca funkcj, wywoamy ope-
rator

typeof

, zwróci on acuch znaków

"function"

.

>>> function f(){return 1;}
>>> typeof f

"function"

Zatem: funkcje w jzyku JavaScript s specjalnym typem danych. Posiadaj dwie istotne cechy:

Q

zawieraj kod,

Q

s wykonywalne (mog by wywoywane).

Wiesz ju, e funkcje wywouje si poprzez podanie nawiasu po ich nazwie. Nastpny przy-
kad pokazuje, e ta metoda zadziaa niezalenie od sposobu definicji funkcji. Wida w nim
take, e funkcja jest traktowana jak normalna warto, któr mona przypisa nowej zmien-
nej lub nawet wykasowa.

>>> var sum = function(a, b) {return a + b;}
>>> var add = sum;
>>> delete sum

true

background image

JavaScript. Programowanie obiektowe

84

>>> typeof sum;

"undefined"

>>> typeof add;

"function"

>>> add(1, 2);

3

Poniewa funkcje to dane przypisane do zmiennych, stosujemy t sam konwencj nazw co
przy nazywaniu zmiennych — nazwa funkcji nie moe zaczyna si liczb i moe zawiera
dowoln kombinacj liter, cyfr oraz znaku podkrelnika.

Funkcje anonimowe

JavaScript pozwala na rozrzucanie fragmentów danych po caym programie. Wyobra sobie,
e Twój program zawiera nastpujcy fragment kodu:

>>> "test"; [1,2,3]; undefined; null; 1;

Kod wyglda do dziwnie, poniewa nie robi nic poytecznego, jednak jest poprawny i nie
spowoduje bdu. Mona powiedzie, e zawiera dane anonimowe, czyli nieprzypisane do
adnej zmiennej i nieposiadajce nazwy.

Wiesz ju, e funkcje mona traktowa jak wszystkie inne dane. W zwizku z tym ich take
mona uywa bez podania nazwy:

>>> function(a){return a;}

Anonimowe fragmenty danych w kodzie nie mog by zbyt przydatne, chyba e s funkcjami.
W takim wypadku istniej dwa bardzo eleganckie zastosowania tych danych:

Q

Funkcj anonimow mona przekaza jako parametr do innej funkcji. Funkcja
odbierajca ten parametr moe przeprowadzi operacje na otrzymanej funkcji.

Q

Funkcje anonimowe mone definiowa i od razu uruchamia.

Przyjrzyjmy si uwaniej obu zastosowaniom funkcji anonimowych.

Wywoania zwrotne

Skoro funkcje to dane, które mona przypisa zmiennym, to mona je definiowa, kasowa,
kopiowa… Dlaczego zatem nie miaoby by moliwe przekazywanie ich jako parametrów do
innych funkcji?

background image

Rozdzia 3. • Funkcje

85

Oto przykad funkcji, która pobiera dwie funkcje jako parametry, wywouje je, po czym zwra-
ca wynik bdcy sum zwróconych przez nie wartoci:

function wywolaj_i_dodaj(a, b){
return a() + b();
}

Zdefiniujmy teraz dwie pomocnicze funkcje, które bd zwracay ustalone wartoci:

function jeden() {
return 1;
}
function dwa() {
return 2;
}

Moemy przekaza je oryginalnej funkcji i obejrze wynik:

>>> wywolaj_i_dodaj(jeden, dwa);

3

Jako parametry mona take przekazywa funkcje anonimowe. Wówczas zamiast definiowania

jeden()

i

dwa()

wystarczyoby napisa:

wywolaj_i_dodaj(function(){return 1;}, function(){return 2;})

Jeli funkcja A zostaje przekazana funkcji B i B wywouje A, czsto mówi si, e A jest wy-
woaniem zwrotnym
(ang. callback function). Jeli A nie ma nazwy, to jest anonimowym wy-
woaniem zwrotnym.

Jakie zastosowania maj takie funkcje? Spójrzmy na przykady, które ilustruj nastpujce
zalety wywoa zwrotnych:

Q

Mona przekazywa funkcje bez koniecznoci ich nazywania, co oznacza, e
potrzebnych jest mniej zmiennych globalnych.

Q

Jeli przeniesiemy obowizek wywoania funkcji na inn funkcj, nasz kod bdzie
krótszy.

Q

Wywoania zwrotne mog korzystnie wpyn na wydajno aplikacji.

Przykady wywoa zwrotnych

Przeanalizujmy czsty scenariusz: mamy funkcj, która zwraca warto, przekazywan na-
stpnie kolejnej funkcji. W naszym przykadzie pierwsza funkcja,

pomnozRazyDwa()

, przyjmuje

trzy parametry, przechodzi przez nie w ptli oraz zwraca tablic zawierajc wynik. Druga
funkcja,

dodajJeden()

, pobiera warto, dodaje do niej jeden, po czym zwraca wynik.

background image

JavaScript. Programowanie obiektowe

86

function pomnozRazyDwa(a, b, c) {
var i, ar = [];
for(i = 0; i < 3; i++) {
ar[i] = arguments[i] * 2;
}
return ar;
}
function dodajJeden(a) {
return a + 1;
}

Przetestujmy te funkcje:

>>> pomnozRazyDwa(1, 2, 3);

[2, 4, 6]

>>> dodajJeden(100)

101

Zaómy teraz, e chcemy, by tablica

myarr

zawieraa trzy elementy, z których kady przejdzie

przez obie funkcje. Zacznijmy od

pomnozRazyDwa()

.

>>> var myarr = [];
>>> myarr = pomnozRazyDwa(10, 20, 30);

[20, 40, 60]

Moemy teraz wywoywa funkcj

dodajJeden()

w ptli, raz dla kadego elementu tablicy:

>>> for (var i = 0; i < 3; i++) {myarr[i] = addOne(myarr[i]);}
>>> myarr

[21, 41, 61]

Wszystko zadziaa, ale jest tu pole do poprawek. Po pierwsze, przykad uruchamia dwie ptle,
które mog by kosztowne, jeli powtórze jest wiele. dany wynik mona otrzyma przy
uyciu jednej tylko ptli. Oto, jak zmieni funkcj

pomnozRazyDwa()

tak, by jako parametr

przyjmowaa funkcj i wywoywaa j przy kadej iteracji:

function pomnozRazyDwa(a, b, c, callback) {
var i, ar = [];
for(i = 0; i < 3; i++) {
ar[i] = callback(arguments[i] * 2);
}
return ar;
}

Zmieniona wersja funkcji pozwala na wykonanie tej samej pracy przy pomocy jednego wy-
woania. Przekazuje si do niego wartoci pocztkowe oraz funkcj, która ma zosta wywoana
na kadej z tych wartoci.

background image

Rozdzia 3. • Funkcje

87

>>> myarr = pomnozRazyDwa(1, 2, 3, dodajJeden);

[3, 5, 7]

Zamiast definiowania funkcji

dodajJeden()

mona skorzysta z funkcji anonimowej, dziki

czemu zdefiniowana zostanie jedna zmienna globalna mniej.

>>> myarr = pomnozRazyDwa(1, 2, 3, function(a){return a + 1});

[3, 5, 7]

Oczywicie tej samej funkcji mona jako parametr przekaza róne funkcje anonimowe:

>>> myarr = multiplyByTwo(1, 2, 3, function(a){return a + 2});

[4, 6, 8]

Funkcje samowywoujce si

Omówilimy ju funkcje anonimowe i wywoania zwrotne. Przejd my teraz do innego zastosowa-
nia funkcji anonimowych — wywoywania funkcji zaraz po ich zdefiniowaniu. Oto przykad:

(
function(){
alert('uuu!');
}
)()

Pocztkowo moe to wyglda gro nie, ale tak naprawd to proste — funkcj anonimow
umieszcza si w nawiasie, po którym nastpuje inny nawias (w przykadzie jest pusty). Drugi
nawias oznacza „uruchom teraz”. To w nim umieszcza si ewentualne parametry funkcji.

(
function(imie){
alert('Cze ' + imie + '!');
}
)('stary')

Jedn z zalet samowywoujacych si funkcji anonimowych jest to, e kod zostanie wykonany
bez tworzenia nadmiaru zmiennych. Minus jest taki, e tej samej funkcji nie da si uruchomi
dwukrotnie (chyba e znajdzie si wewntrz ptli lub innej funkcji). Dlatego anonimowe funkcje
samowywoujce najlepiej nadaj si do wykonywania jednokrotnych zada inicjalizacyjnych.

Funkcje wewntrzne (prywatne)

Skoro funkcje s zwykymi wartociami, nic nie stoi na przeszkodzie, by zdefiniowa funkcj
wewntrz innej funkcji.

background image

JavaScript. Programowanie obiektowe

88

function a(param) {
function b(theinput) {
return theinput * 2;
};
return 'Wynik wynosi ' + b(param);
};

Stosujc drug notacj definiowania funkcji, moemy napisa:

var a = function(param) {
var b = function(theinput) {
return theinput * 2;
};
return 'Wynik wynosi ' + b(param);
};

Kiedy globalna funkcja

a()

zostanie wywoana, wywoa take lokaln funkcj

b()

. Jako e

b()

jest lokalna, nie jest dostpna spoza

a()

, dlatego nazywamy j funkcj prywatn.

>>> a(2);

"The result is 4"

>>> a(8);

"The result is 16"

>>> b(2);

b is not defined

Ze stosowania funkcji prywatnych pyn nastpujce korzyci:

Q

Nie dochodzi do zamiecenia globalnej przestrzeni nazw (zmniejszone ryzyko
kolizji nazw).

Q

Prywatno: na zewntrz widoczne s tylko te funkcje, które programista chce
udostpni. Funkcjonalnoci nieprzeznaczone dla reszty aplikacji s ukryte.

Funkcje, które zwracaj funkcje

Wspominaem ju, e funkcja zawsze zwraca warto, a jeli nie robi tego w sposób jawny, to
niejawnie zwracana jest warto

undefined

. Funkcja zwraca dokadnie jedn warto, która

z powodzeniem moe by inn funkcj.

function a() {
alert('A!');
return function(){
alert('B!');
};
}

background image

Rozdzia 3. • Funkcje

89

Widoczna powyej funkcja

a()

wykonuje swoj prac (mówi

'A!'

) i zwraca inn funkcj, która

robi co innego (mówi

'B!'

). Wynik mona przypisa jakiej zmiennej i uywa jej jako nor-

malnej funkcji.

>>> var newFunc = a();
>>> newFunc();

Pierwsza linia powyszego kodu spowoduje wywietlenie okienka z wiadomoci

'A!'

, a dru-

ga — okienka z wiadomoci

'B!'

.

Jeli funkcja zwracana przez inn funkcj ma zosta wykonana natychmiast, bez potrzeby
przypisywania jej do nowej zmiennej, wystarczy doda jeszcze jeden nawias. Wynik kocowy
bdzie taki sam jak wczeniej.

>>> a()();

Funkcjo, przepisz e si!

Poniewa funkcje potrafi zwraca funkcje, moliwe jest zastpienie oryginalnej funkcji t
zwracan. Wrómy do poprzedniego przykadu. Warto zwrócon przez wywoanie

a()

mona przypisa zmiennej

a

, nadpisujc w ten sposób istniejc funkcj:

>>> a = a();

Powysza linia przy pierwszym uruchomieniu spowoduje wywietlenie

'A!'

, jednak jej dru-

gie uruchomienie wywietli

'B!'

.

Opisany mechanizm jest przydatny, jeli funkcja wykonuje pewne jednorazowe zadanie. Po
zakoczeniu zadania zmiennej przechowujcej funkcj przypisywana jest nowa warto,
dziki czemu operacje nie musz by powtarzane za kadym razem, gdy kto wywoa funkcj.
W ostatnim przykadzie funkcja zostaa przedefiniowana z zewntrz — pobralimy zwrócon
warto i przypisalimy j funkcji. Jednake moliwe jest równie przepisanie funkcji od rodka.

function a() {
alert('A!');
a = function(){
alert('B!');
};
}

Przy pierwszym wywoaniu funkcja:

Q

Wywietli

'A!'

(zaómy, e to wanie jest nasze jednorazowe zadanie

inicjalizacyjne).

Q

Zmieni definicj globalnej zmiennej

a

, przypisujc jej now funkcj.

Kade kolejne wywoanie bdzie powodowao wywietlenie

'B!'

.

background image

JavaScript. Programowanie obiektowe

90

Oto inny przykad, który czy kilka technik omówionych na ostatnich kilku stronach:

var a = function() {
function inicjalizacja(){
var setup = 'ju';
}
function normalnaPraca() {
alert('praca wre!');
}
inicjalizacja();
return normalnaPraca;
}();

W przykadzie:

Q

Mamy funkcje prywatne:

inicjalizacja()

i

normalnaPraca()

.

Q

Mamy funkcj samowywoujc si: funkcja

a()

jest wywoywana dziki nawiasowi

po jej definicji.

Q

Pierwsze wywoanie

a()

polega na wywoaniu funkcji

inicjalizacja()

i zwróceniu

referencji do zmiennej

normalnaPraca

, która jest funkcj. Zwró uwag na brak

nawiasów przy zwracanej wartoci — nie ma ich dlatego, e zwracamy do funkcji
referencj, a nie wynik wywoania teje funkcji.

Q

Jako e kod zaczyna si od

var a =

, warto zwrócona przez samowywoujc si

funkcj zostanie przypisana zmiennej

a

.

Jeli chcesz sprawdzi, czy poprawnie rozumiesz omówiony zakres materiau, spróbuj odpo-
wiedzie na ponisze pytania. Jakie bdzie zachowanie napisanego przed chwil programu, gdy:

Q

zostanie wgrany po raz pierwszy?

Q

po wgraniu zostanie wywoane

a()

?

Przedstawione mechanizmy okazuj si bardzo przydatne w rodowisku przegldarki. Róne
przegldarki mog realizowa konkretne zadania na róne sposoby. Przy zaoeniu, e waci-
woci przegldarki nie zmieni si pomidzy wywoaniami funkcji, moemy stworzy funkcj,
która wybierze sposób dziaania najlepiej dopasowany do danej przegldarki, po czym w od-
powiedni sposób zmieni swoj definicj, dziki czemu tylko raz bdzie musiaa wykrywa typ
przegldarki. Konkretne przykady zastosowania tego scenariusza bdzie mona zobaczy na
dalszych stronach ksiki.

Domknicia

Pozostaa cz tego rozdziau jest powicona domkniciom (czy istnieje lepszy sposób na
zamknicie rozdziau?). Domknicia pocztkowo mog wydawa si trudne do zrozumienia,
dlatego nie zniechcaj si, jeli nie pojmiesz wszystkiego od razu. Postaraj si doczyta rozdzia

background image

Rozdzia 3. • Funkcje

91

do koca i poeksperymentowa z przykadami, a jeli niektóre zagadnienia nadal nie bd ja-
sne, moesz do nich wróci pó niej, kiedy inne mechanizmy omówione w tym rozdziale nie
bd ju sprawiay Ci adnego kopotu.

Zanim zajmiemy si domkniciami, powtórzmy i rozszerzmy troch pojcia zakresu w jzyku
JavaScript.

acuch zakresów

Jak ju Ci wiadomo, JavaScript nie wyrónia adnych zakresów ograniczonych nawiasami
klamrowymi, ale istnieje zakres funkcji. Zmienna zdefiniowana wewntrz funkcji nie jest wi-
doczna poza t funkcj, natomiast zmienna zdefiniowana wewntrz bloku kodu (np. po

if

lub

w ptli

for

) jest dostpna poza blokiem.

>>> var a = 1; function f(){var b = 1; return a;}
>>> f();

1

>>> b

b is not defined

Zmienna

a

naley do globalnej przestrzeni nazw, podczas gdy zmienna

b

tylko do zakresu

funkcji

f()

. Dlatego:

Q

Wewntrz

f()

widoczne s zarówno

a

i

b

.

Q

Wewntrz

f()

widoczna jest zmienna

a

, ale nie zmienna

b

.

Jeli zdefiniujesz funkcj

n()

osadzon w

f()

,

n()

bdzie miaa dostp do zmiennych ze swo-

jego zakresu, a take do zmiennych swoich „rodziców”. W takim wypadku mówimy o acuchu
zakresów
, który moe by dowolnie dugi (gboki).

var a = 1;
function f(){
var b = 1;
function n() {
var c = 3;
}
}

Zasig leksykalny

Funkcje w jzyku JavaScript maj zasig leksykalny. Oznacza to, e funkcje tworz swoje wa-
sne rodowisko (zakres) podczas definicji, a nie podczas wywoania. Spójrzmy na przykad:

background image

JavaScript. Programowanie obiektowe

92

>>> function f1(){var a = 1; f2();}
>>> function f2(){return a;}
>>> f1();

a is not defined

Wewntrz funkcji

f1()

wywoujemy funkcj

f2()

. Poniewa zmienna lokalna

a

znajduje si

take wewntrz

f1()

, kto mógby si spodziewa, e

f2()

bdzie miaa dostp do

a

, jednak

tak nie jest. W momencie definicji

f2()

(a nie w momencie wywoania) nigdzie nie byo ladu

a

.

f2()

, podobnie jak

f1()

, ma dostp jedynie do wasnego zakresu oraz do zakresu globalnego.

f1()

i

f2()

nie wspódziel zakresów lokalnych.

Podczas definiowania funkcja zapamituje swoje rodowisko, to znaczy swój acuch zakresów.
Nie znaczy to wcale, e funkcja pamita kad konkretn zmienn, która pojawia si w tym
zakresie. Wrcz przeciwnie — zmienne mona dodawa, usuwa i uaktualnia, a funkcja zawsze
bdzie widziaa najnowszy, aktualny stan zmiennych. Jeli rozszerzymy przykad o deklaracj
globalnej zmiennej

a

, stanie si ona widoczna dla

f2()

, poniewa

f2()

zna ciek do zmiennych

globalnych i ma dostp do caoci tego rodowiska. Zwró uwag na to, e

f1()

zawiera wywo-

anie

f2()

, które dziaa — mimo e

f2()

nie zostaa jeszcze zdefiniowana.

f1()

musi tylko po-

siada wiedz o wasnym zakresie, by wszystko, co si w nim pojawi, stawao si automatycznie
dostpne dla

f1()

.

>>> function f1(){var a = 1; f2();}
>>> function f2(){return a;}
>>> f1();

a is not defined

>>> var a = 5;
>>> f1();

5

>>> a = 55;
>>> f1();

55

>>> delete a;

true

>>> f1();

a is not defined

Przedstawiony mechanizm sprawia, e JavaScript jest bardzo elastyczny — mona dodawa
zmienne, usuwa je, a potem dodawa je ponownie. Moesz poeksperymentowa, kasujc
funkcj

f2()

, a potem definiujc j ponownie, ale z innym ciaem. Funkcja

f1()

nadal bdzie

dziaa, poniewa musi zna jedynie sposób dostpu do swojego zakresu — nie jest jej po-
trzebna wiedza o tym, co kiedy do tego zakresu naleao. Cig dalszy przykadu:

background image

Rozdzia 3. • Funkcje

93

true
>>> f1()

f2 is not defined

>>> var f2 = function(){return a * 2;}
>>> var a = 5;

5

>>> f1();

10

Przerwanie acucha za pomoc domknicia

Zaczniemy od ilustracji.

Poniej widzisz zakres globalny. Wyobra go sobie jako wszechwiat.

Moe on zawiera zmienne, takie jak

a

, i funkcje, jak

F

.

Funkcje posiadaj wasn przestrze, któr mog wykorzystywa do przechowywania innych
zmiennych (i funkcji). W pewnym momencie rysunek bdzie wyglda mniej wicej tak:

background image

JavaScript. Programowanie obiektowe

94

Jeli jeste w punkcie

a

, jeste w przestrzeni globalnej. Jeli w punkcie

b

, który naley do

przestrzeni funkcji

F

, masz dostp do przestrzeni globalnej oraz do przestrzeni

F

. Jeli znala-

ze si w punkcie

c

, który naley do funkcji

N

, moesz sign do przestrzeni globalnej, prze-

strzeni

F

oraz

N

. Nie da si sign z

a

do

b

, poniewa punkt

b

nie jest widoczny poza

F

. Moesz

natomiast uzyska dostp z

c

do

b

lub z

N

do

b

. Ciekawe rzeczy (domknicie) zaczynaj si

dzia, gdy jakim sposobem

N

wydostaje si z

F

i trafia do przestrzeni globalnej.

Co si wtedy dzieje?

N

jest w tej samej przestrzeni globalnej co

a

. Jako e funkcje pamitaj

rodowisko, w którym zostay zdefiniowane,

N

nadal ma dostp do przestrzeni

F

, a co za tym

idzie dostp do

b

. Jest to ciekawe dlatego, e

N

znajduje si tam gdzie

a

, a jednak

N

ma dostp

do

b

, za

a

nie.

Jak

N

udaje si przerwa acuch? Istniej dwa sposoby:

N

moe zosta zmienn globaln

(pominicie

var

) lub moe zosta zwrócona przez

F

do przestrzeni globalnej. Zobaczmy, jak to

wyglda w praktyce.

Domknicie 1.

Przyjrzyj si uwanie tej funkcji:

function f(){
var b = "b";
return function(){
return b;
}
}

background image

Rozdzia 3. • Funkcje

95

Funkcja zawiera lokaln zmienn

b

, która nie jest dostpna z przestrzeni globalnej:

>>> b

b is not defined

Zwró uwag na warto zwracan przez

f()

: jest ona inn funkcj. Moesz o niej myle jako

o

N

z przedstawionych powyej rysunków. Nowa funkcja ma dostp do swojej przestrzeni

prywatnej, do przestrzeni funkcji

f()

oraz do przestrzeni globalnej. Widzi zatem równie

b

.

Poniewa

f()

mona wywoa w przestrzeni globalnej (jest funkcj globaln), moesz j wy-

woa i przypisa zwracan przez ni warto innej zmiennej globalnej. Wynikiem bdzie
nowa funkcja globalna, która ma dostp do prywatnej przestrzeni

f()

.

>>> var n = f();
>>> n();

"b"

Domknicie 2.

Przykad, który nastpi za chwil, pozwala uzyska ten sam wynik co przykad wczeniejszy,
jednak z zastosowaniem nieco innych metod. Funkcja

f()

nie bdzie zwracaa funkcji, a za-

miast tego utworzy now, globaln funkcj

n()

wewntrz swojego ciaa.

Zacznijmy od deklaracji zmiennej, do której pó niej przypiszemy now funkcj. Nie jest to
obowizkowe, ale zawsze warto deklarowa zmienne. Definicja funkcji

f()

moe wyglda tak:

var n;
function f(){
var b = "b";
n = function(){
return b;
}
}

Co si stanie po wywoaniu

f()

?

>>> f();

Wewntrz przestrzeni

f()

definiowana jest nowa funkcja. Poniewa nie zostaa uyta instruk-

cja

var

, funkcja jest globalna. W czasie definicji funkcja

n()

znajdowaa si wewntrz

f()

, zatem

ma dostp do zakresu zmiennych

f()

.

n()

zachowa prawo dostpu nawet wtedy, gdy stanie si

czci przestrzeni globalnej.

>>> n();

"b"

background image

JavaScript. Programowanie obiektowe

96

Domknicie 3. i jedna definicja

W oparciu o to, co zostao powiedziane do tej pory, moemy powiedzie, e domknicie jest
tworzone, gdy funkcja zachowuje dostp do zakresu rodzica po tym, jak rodzic zwróci j do
globalnej przestrzeni nazw.

Argument przekazany funkcji wewntrz niej jest dostpny jako zmienna globalna. Moesz stwo-
rzy funkcj zwracajc inn funkcj, która z kolei zwraca argument przekazany rodzicowi.

function f(arg) {
var n = function(){
return arg;
};
arg++;
return n;
}

Funkcj mona wywoa w nastpujcy sposób:

>>> var m = f(123);
>>> m();

124

Zauwa, e zmienna

arg

zostaa zwikszona ju po definicji funkcji, a pomimo tego

m()

zwrócia

aktualn warto. Jest to kolejny dowód na to, e funkcje s zwizane ze swoimi zakresami, a nie
z przechowywanymi tam w danym momencie zmiennymi i ich wartociami.

Domknicia w ptli

Poka teraz co, co czsto prowadzi do bardzo trudnych do wykrycia bdów, poniewa na
pierwszy rzut oka wydaje si, e nie ma tam miejsca na pomyk.

Napiszmy ptl o trzech iteracjach, która za kadym przebiegiem zwraca numer ptli. Funk-
cje zostan dodane do tablicy, która na koniec zostanie zwrócona. Oto nasza funkcja:

function f() {
var a = [];
var i;
for(i = 0; i < 3; i++) {
a[i] = function(){
return i;
}
}
return a;
}

background image

Rozdzia 3. • Funkcje

97

Wywoajmy j teraz, przypisujc wynikow tablic zmiennej

a

.

>>> var a = f();

Mamy zatem tablic z trzema funkcjami. Wywoajmy je, podajc nawiasy po kadym elemen-
cie tablicy. Oczekiwane zachowanie to wypisanie numerów iteracji:

0

,

1

i

2

. Spróbujmy:

>>> a[0]()

3

>>> a[1]()

3

>>> a[2]()

3

Hm, niezupenie to mielimy na myli. Co si stao? Utworzylimy trzy domknicia, które
wskazuj na t sam lokaln zmienn

i

. Domknicia nie pamitaj wartoci, tylko przechowuj

referencj do zmiennej

i

— dlatego zwracaj jej aktualn warto. Po wyjciu z ptli wartoci

zmiennej

i

jest 3. Wszystkie funkcje wskazuj na t sam warto.

(Dla lepszego zrozumienia ptli zastanów si, dlaczego wartoci

i

jest

3

, a nie

2

).

Jak zatem zaimplementowa poprawne zachowanie? Potrzebne nam s trzy róne zmienne.
Eleganckie rozwizanie polega na wykorzystaniu kolejnego domknicia:

function f() {
var a = [];
var i;
for(i = 0; i < 3; i++) {
a[i] = (function(x){
return function(){
return x;
}
})(i);
}
return a;
}

Uzyskamy oczekiwany wynik:

>>> var a = f();
>>> a[0]();

0

>>> a[1]();

1

background image

JavaScript. Programowanie obiektowe

98

>>> a[2]();

2

W tej wersji nie tworzymy funkcji zwracajcej

i

, tylko przekazujemy

i

innej, samowywouj-

cej si funkcji. W tej funkcji

i

staje si lokaln zmienn

x

i za kadym razem ma inn warto.

Ten sam wynik mona uzyska przy uyciu „normalnej” (czyli niesamowywoujcej si) funkcji
wewntrznej. Kluczem do sukcesu jest wykorzystanie rodkowej funkcji do ustalenia wartoci

i

podczas danej iteracji.

function f() {
function makeClosure(x) {
return function(){
return x;
}
}
var a = [];
var i;
for(i = 0; i < 3; i++) {
a[i] = makeClosure(i);
}
return a;
}

Funkcje dostpowe

Chc opowiedzie o jeszcze dwóch sposobach wykorzystania domkni. Pierwszy z nich po-
lega na utworzeniu funkcji dostpowych get (pobranie wartoci) i set (ustawienie wartoci).
Zaómy, e posiadasz zmienn, która moe przyjmowa wartoci tylko ze cile okrelonego
zbioru. Nie chcesz odkrywa tej zmiennej, poniewa chcesz zabezpieczy si przed sytuacj,
w której pewien fragment kodu nada jej niedozwolon warto. Rozwizaniem jest utworze-
nie schronienia dla tej zmiennej wewntrz pewnej funkcji i stworzenie dwóch dodatkowych
funkcji, które bd odczytyway i ustawiay jej warto. Funkcja ustawiajca warto moe
zawiera pewn logik, która nie pozwoli na nadanie zmiennej wartoci spoza dozwolonego
zbioru (jednak dla uproszczenia przykadu pomimy walidacj).

Funkcje dostpowe powinny znale  si wewntrz tej samej funkcji, która zawiera tajn zmienn,
tak by dzieliy ten sam zakres:

var getValue, setValue;
(function() {
var secret = 0;
getValue = function(){
return secret;
};

background image

Rozdzia 3. • Funkcje

99

setValue = function(v){
secret = v;
};
})()

Funkcja, która opakowuje zmienn i dwie funkcje dostpowe, jest tutaj samowywoujc si
funkcj anonimow. Definiuje ona

setValue()

i

getValue()

jako funkcje globalne, podczas

gdy zmienna

secret

pozostaje lokalna i nie jest dostpna bezporednio.

>>> getValue()

0

>>> setValue(123)
>>> getValue()

123

Iterator

Ostatni przykad domknicia (a zarazem ostatni przykad w tym rozdziale) pokazuje wykorzy-
stanie domkni w celu osignicia funkcjonalnoci iteratora.

Wiesz ju, jak wykorzysta ptl do przejcia przez wszystkie elementy zwykej tablicy. Mo-
esz jednak napotka bardziej zoon struktur danych, w której kolejno elementów jest
okrelana przez bardziej zoony zestaw regu. Wówczas skomplikowan logik rozwizujc
problem „kto nastpny?” umieszczasz w wygodnej w uyciu funkcji

next()

. Nastpnie wywou-

jesz

next()

za kadym razem, gdy chcesz pobra kolejn warto. Na potrzeby przykadu wy-

korzystamy jednak zwyk tablic, a nie zoon struktur danych.

Oto funkcja inicjalizacyjna, która pobiera tablic, a take definiuje prywatny wska nik

i

, zaw-

sze wskazujcy nastpny element w tablicy:

function setup(x) {
var i = 0;
return function(){
return x[i++];
};
}

Wywoanie funkcji

setup()

z parametrem bdcym tablic danych spowoduje automatyczne

utworzenie funkcji

next()

.

>>> var next = setup(['a', 'b', 'c']);

Dalej czekaj nas sam przyjemnoci: wywoujc wci t sam funkcj, przejdziemy przez
wszystkie elementy tablicy.

background image

JavaScript. Programowanie obiektowe

100

>>> next();

"a"

>>> next();

"b"

>>> next();

"c"

Podsumowanie

Wanie skoczylimy podstawowy kurs poj zwizanych z funkcjami. Przejcie do konceptów
programowania obiektowego oraz do wzorców wykorzystywanych w nowoczesnym progra-
mowaniu w jzyku JavaScript powinno by dla Ciebie proste. Do tej pory unikalimy funkcjo-
nalnoci obiektowych, ale od tej chwili nie bdziemy ju tego robi. Powtórzmy materia przed-
stawiony w tym rozdziale. Omówione zostay nastpujce kwestie:

Q

Definiowanie i wywoywanie funkcji.

Q

Parametry funkcji i ich elastyczno.

Q

Funkcje wbudowane:

parseInt()

,

parseFloat()

,

isNaN()

,

isFinite()

,

eval()

,

a take cztery funkcje do kodowania i dekodowania adresów URL.

Q

Zakres zmiennych: nie ma zakresu zwizanego z nawiasami klamrowymi, istnieje
zakres funkcji, funkcje maj zakres leksykalny, obowizuje zasada acucha zakresów.

Q

Funkcje to dane — funkcj mona przypisa zmiennej, z czego wynika szereg
ciekawych zastosowa, wród których mona wymieni:

Q

prywatne funkcje i zmienne,

Q

funkcje anonimowe,

Q

wywoania zwrotne,

Q

samowywoujce si funkcje,

Q

funkcje zmieniajce swoj definicj.

Q

Domknicia.

wiczenia

1.

Napisz funkcj, która przeksztaca szesnastkow definicj koloru (np. niebieski

to

"0000FF"

) na reprezentacj RGB (np. "rgb(0, 0, 255)"). Nazwij funkcj

getRGB()

i przetestuj j za pomoc nastpujcego kodu:

background image

Rozdzia 3. • Funkcje

101

>>> var a = getRGB("#00FF00");
>>> a;

"rgb(0, 255, 0)"

2.

Co pojawi si w konsoli po uruchomieniu kadej z poniszych linii kodu?

>>> parseInt(1e1)
>>> parseInt('1e1')
>>> parseFloat('1e1')
>>> isFinite(0/10)
>>> isFinite(20/0)
>>> isNaN(parseInt(NaN));

3.

Co pojawi si w okienku

alert()

po wykonaniu nastpujcego kodu?

var a = 1;
function f() {
var a = 2;
function n() {
alert(a);
}
n();
}
f();

4.

Wszystkie ponisze przykady spowoduj wywietlenie

"Uuu!"

. Czy potrafisz

powiedzie dlaczego?

4.1

var f = alert;
eval('f("Uuu!")');

4.2

var e;
var f = alert;
eval('e=f')('Uuu!');

4.3

(
function(){
return alert;
}

)()('Uuu!');


Wyszukiwarka

Podobne podstrony:
informatyka javascript programowanie obiektowe stoyan stefanov ebook
JavaScript Zasady programowania obiektowego
JavaScript Zasady programowania obiektowego 2
JavaScript Zasady programowania obiektowego
JavaScript Zasady programowania obiektowego jascpo
Programowanie obiektowe(ćw) 1
Zadanie projekt przychodnia lekarska, Programowanie obiektowe
Programowanie obiektowe w PHP4 i PHP5 11 2005
Programowanie Obiektowe ZadTest Nieznany
Egzamin Programowanie Obiektowe Głowacki, Programowanie Obiektowe

więcej podobnych podstron