İsmoş üçün JavaScript
Əgər JavaScript üzrə mütəxəssis olmaq fikriniz varsa, onda gərək dilin semantikini tam şəkildə qavrayasınız. Bu yazıda giriş olaraq JavaScript-i diaqramlar əlavə edərək ətraflı izah etməyə çalışacağam.
Referanslar
JavaSript-də var olan dəyişənlər əslində bir etiket olub yaddaşda hər hansı bir yeri referans edirlər. Bu dəyərlər string-lər, rəqəmlər və boolean-lar kimi primitivlər ola bilər. Həmçinin obyekt və funksiya da olma imkanı var.
Lokal Dəyişənlər
Aşağıdakı kod misalında, dörd ədəd lokal dəyişəni top scope-da (üst əhatə sahəsində) yaradmış olacayıq.
var name = "Tim Caswell" var age = 28 var isProgrammer = true; var likesJavaScript = true; isProgrammer === likesJavaScript
İki boolean dəyişəni yaddaşda eyni dəyəri işarə edir. Bu ona görədir ki, primitivlər dəyişməzdir. VM (Virtual Maşın -JavaScript-i şərh edir və işlədir) tək bir misalı bütün referanslar arasında müəyyən dəyər üçün effektivləşdirə və paylaşa bilər.
Kodda isProgrammer (proqramçıdır) === likesJavaScript (JavaScript-i bəyənir) olan hissə əslində iki fərqli referans olub eyni dəyəri işarə edirlər. Ona görə də, cavab true (doğru) olaraq gəlir.
Yuxarıdakı qutu ən uzaq closure scope (qapanma sahəsini) təmsil edir. Bu dəyişənlər üst səviyə lokal dəyişənləridir. Global/Window obyekt xüsusiyyətləri ilə qarışdırılmamalıdır.
if-else Şərtləri
</code><code class=" language-javascript"><span class="token keyword">if</span><span class="token punctuation">(</span>isProgrammer <span class="token operator">===</span> likesJavaScript<span class="token punctuation">)</span> <span class="token punctuation">{</span> </code></pre> <pre class=" language-javascript"><code class=" language-javascript"> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token string">'Lap Əla!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token string">'Fərqli zövqlərə gərək hörmətlə yanaşaq'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">} </span></code><code class=" language-javascript"><span class="token punctuation"><code class=" language-javascript">
Əgər proqramçı JavaScript-i bəyənirsə lap əla. Yox, əgər bəyənmirsə yenə də hörmətimizi qoruyaq. İf-lərin içinə funksiya da yaza bilərsiniz.
Məsələn, əgər funksiyadan gələn cavab müsbət olsa digər addıma keçmək olar. Əlavə olaraq else-if şərt halı da mövcuddur. Onu siz özünüz koda
əlavə edərək rahatca öyrənə bilərsiniz.
Gəlin Biraz Dövr Edək
</code></span></code><code class=" language-javascript"><span class="token comment">// for operatoru </span><span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token string">'i 5-dən hələ də kiçikdir'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment"> // do-while operatoru </span><span class="token keyword">do</span> <span class="token punctuation">{</span> i<span class="token operator">++</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">while</span><span class="token punctuation">(</span>i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment"> // while operatoru </span><span class="token keyword">while</span><span class="token punctuation">(</span>i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token string">'i 5-dən hələ də kiçikdir'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment"> // while operatoru sonsuz dövr </span><span class="token keyword">while</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token string">'break əlavə etməsən sonsuza qədər burdayam'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment"> // for-in operatoru </span><span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">"Huseyn"</span><span class="token punctuation">,</span> age<span class="token punctuation">:</span> <span class="token number">24</span><span class="token punctuation">,</span> job<span class="token punctuation">:</span> <span class="token string">'programmer'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span>obj<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment"> // for-of operatoru </span><span class="token keyword">var</span> array <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'1'</span><span class="token punctuation">,</span><span class="token string">'2'</span><span class="token punctuation">,</span><span class="token string">'Huseyn'</span><span class="token punctuation">,</span><span class="token string">'24'</span><span class="token punctuation">,</span><span class="token string">'programmer'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i of array<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">} </span></code><code class=" language-javascript"><span class="token punctuation"><code class=" language-javascript">
İlk dövr operatorunda, yəni for operatorunda, ilk olaraq “i” dəyişəninə 0 verilir, ilk yoxlanış olunur, əgər “i” 5-dən kiçikdirsə ekrana yazını yazdırır. Sonra qayıdır i-yə 1 əlavə edərək təzədən yoxlayır və beləcə davam edir. Do-while operatoru da eyni işi görür. For operatorundan fərqli olaraq ən az 1 dəfə də olsa ekrana yazını yazdırır. Çünki ilk
yoxlanış yazını yazdıqdan sonra baş verir. While da həmçinin eyni işi görür. While-da təhlükəli olan bir şey var ki, əgər düzgün şərt müəyyən edilməsə sonsuza qədər dövr edəcək. For-in operatorunun obyetklər üçün istifadə olunması daha məsləhətlidir. For-of operatoru isə array-in (massivin) dəyərlərini ekrana tək-tək yazdırır. Bunların yerini
dəyişərək fərqlərini müşahidə edə bilərsiniz. Təcrübə qazandıqca da harada hansı dövr operatorundan istifadə etməyin lazım olduğunu daha yaxşı biləcəksiniz.
Obyetklər və Prototip Zəncirləri
Obyektlər, yeni obyektlərə və prototiplərə olan bir çox referansın cəmi kimi düşünülə bilər. Burada ən əsas mətləb odur ki, obyektlər prototip zənciri əlavə etmiş olur. Yəni bu o deməkdir ki, əgər mən hər hansı bir dəyişəni əldə etmək istəyirəmsə, obyekt bunu əgər hal-hazırda özündə varsa gətirəcək. Yox, əgər mən istədiyim dəyişən obyektin özündə
yoxdursa, ata obyekt adlanan obyektdən gətirməyə çalışacaq.
</code></span></code> <code class=" language-javascript"><span class="token comment">// Ata obyekt </span><span class="token keyword">var</span> tim <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">"Tim Caswell"</span><span class="token punctuation">,</span> age<span class="token punctuation">:</span> <span class="token number">28</span><span class="token punctuation">,</span> isProgrammer<span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span> likesJavaScript<span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span> <span class="token comment"> //Bala obyekt </span><span class="token keyword">var</span> jack <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create<span class="token punctuation">(</span></span>tim<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment"> //Bəzi xüsusiyyətlərin üzərinə təkrar yaz </span>jack<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"Jack Caswell"</span><span class="token punctuation">;</span> jack<span class="token punctuation">.</span>age <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span> <span class="token comment"> //Prototip zənciri vasitəsi ilə axtar </span>jack<span class="token punctuation">.</span>likesJavaScript </code> <code class=" language-javascript"><span class="token punctuation"><code class=" language-javascript">
Tim dəyişəni tərəfindən referans olunan dörd xüsusiyyətli bir obyektimiz var. İkinci obyekt isə birinci obyetkdən inherit (varis) olur və jack tərəfindən referans olunur. Daha sonra iki xüsusiyyəti təzədən yazmış olduq.
Deməli, jack.likesJavaScript-i axtardığımız vaxt ilk olaraq jack-in referans etdiyi obyekti tapırıq. O obyektə likesJavaScript dəyişəni olmadığına görə ata obyektə gedirik. Axırda likesJavaScript-in true dəyərini referans etdiyini tapmış oluruq.
Qlobal Obyekt
jslint kimi vasitələrdən istifadə etmisinizsə yəqin ki orada dəyişənlərdən əvvəl “var
əlavə etmək yadınızdan çıxmasın” kimi xəbərdarlıq ilə qarşılaşmısınız. Bəs yadınızdan çıxsa necə?
</code></span></code> var</span> name <span class="token operator">=</span> <span class="token string">"Tim Caswell"</span><span class="token punctuation">;</span> <span class="token keyword">var</span> age <span class="token operator">=</span> <span class="token number">28</span><span class="token punctuation">;</span> <span class="token keyword">var</span> isProgrammer <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span> likesJavaScript <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span><span class="token comment"> // var yaddan çıxdı </span></code><code class=" language-javascript"><span class="token punctuation"><code class=" language-javascript">
Gördüyünüz kimi likesJavaScript hal-hazırda Qlobal obyektin xüsusiyyəti halına çevrilib. Yəni outer closure (xarici qapanma demək olar yəqin ki) yerinə qlobal obyektin xüsusiyyəti halına gəlib. Əslində bu bir neçə skripti arışdırsanız bir məna verə bilər. Problem də odur ki, hər hansı bir real proqramda bu belə olacaq.
Həmişə var
ifadəsini dəyişənlərin əvvəlinə əlavə edin ki, dəyişənlərinizin sahəsi hazırki closure-a (qapanmaya) və onun balalarına tutulsun. Bu qaydaya riayət etsəniz daha çox xoşbəxt ola bilərsiniz.
Əgər Qlobal obyektə nəsə əlavə etmək istəsəniz bunu açıq şəkildə edin. Məsələn, window.too brazur-də və ya node.js-də global.too olaraq.
Funksiyalar və Qapanmalar (Closure)
JavaScript-də funksiyalar zəncirli əhatə sahəsi (scope) və qapanmalar (closure) yaradmağa malikdirlər.
Qapanmaların Göstərimi
Funksiya, işlədilə bilən kod və xüsusiyyətləri tutan xüsusi bir obyekt kimi düşünülə bilər. Hər funksiyanın xüsusi bir əhatə sahəsi vardır. Hansı ki, funksiya yaradılan vaxt onun var olduğu mühiti referans edir. Əgər funksiya bir başqa funksiyadan gəlirsə (return edilibsə) onda əhatə sahəsinə olan köhnə referans yeni funksiya tərəfindən qapanmış olur.
Aşağıdakı misalda sadə bir metod yaradaraq qapanmanı göstərməyə çalışaq.
</code></span></code>function</span> <span class="token function">makeClosure<span class="token punctuation">(</span></span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> name<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment"> // Yeni funksiya tərəfindən qapanma olacaq </span><span class="token keyword">var</span> description1 <span class="token operator">=</span> <span class="token function">makeClosure<span class="token punctuation">(</span></span><span class="token string">"Cloe the Closure"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> description2 <span class="token operator">=</span> <span class="token function">makeClosure<span class="token punctuation">(</span></span><span class="token string">"Albert the Awesome"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token function">description1<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token function">description2<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation"><code class=" language-javascript">
description1() çağırılan zaman, VM referans etdiyi funksiyaya baxaraq onu işlədməyə çalışır. Bu funksiya isə lokal dəyişən olan name
üçün baxanda onu qapanmış olan sahədə tapır. Bu yaxşı bir şeydir, çünki hər funksiyanın lokal dəyişənləri üçün öz sahəsi mövcuddur.
Java ilə tanış olananların JavaScript-də private dəyişənlər necə yaradılır kimi suallarına cavab qapanmadır.
Paylaşılan Funksiyalar və this
Bəzən performans səbəblərinə görə və ya sən bu tərzi bəyəndiyinə görə, JavaScript this
açar sözü ilə təmin edir. Bu bizə funksiya obyektini çağırılışa görə fərqli əhatə sahələrində istifadə etməyə icazə verir.
Aşağıdakı misalda this
-in çağrılışdan çağrılışa necə dəyişdiyinin şahidi olabilərik.
</code></span><span class="token keyword">var</span> Lane <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">"Lane the Lambda"</span><span class="token punctuation">,</span> description<span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">var</span> description <span class="token operator">=</span> Lane<span class="token punctuation">.</span>description<span class="token punctuation">;</span> <span class="token keyword">var</span> Fred <span class="token operator">=</span> <span class="token punctuation">{</span> description<span class="token punctuation">:</span> Lane<span class="token punctuation">.</span>description<span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Fred the Functor"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment"> // Funksiyanı 4 fərqli sahədən çağır </span>console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span>Lane<span class="token punctuation">.</span><span class="token function">description<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span>Fred<span class="token punctuation">.</span><span class="token function">description<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span><span class="token function">description<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log<span class="token punctuation">(</span></span>description<span class="token punctuation">.</span><span class="token function">call<span class="token punctuation">(</span></span><span class="token punctuation">{</span>name<span class="token punctuation">:</span><span class="token string">"Zed the Zetabyte"</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation"><code class=" language-javascript">
Diaqramdan görə bilərik ki, Fred.description-a Lane.description təyin edilib. Bu sadəcə funskiyasını referans etmiş olur. Ona görə də bu üç referansların hamısının gizli description funksiya üzərində eyni dərəcəli sahibliyi var.
Bir kiçik mövzuya toxunmaq istəyirəm. Deməli, JavaScript-də C ya da Java kimi həm funksiya həm də bloklarda fərqli əhatə sahəsi yaradma deyə bir şey yoxdur. Yəni C ailəsinə mənsub dillər də blok (if-else, dövr, funksiya və s.) arasında yaradılan dəyişənlərə qıraq-bucaqdan müdaxilə etmək olmur və blok işini tamamladıqdan sonra dəyişənləri də azad etmiş olur. Bu yaxşı şeydir. Ona görə də, elə dillər də məsləhət odur ki, blokun içində istifadə olunacaq dəyişən hələ blokun içində yaradılsın. Amma JavaScript-də bu ancaq funksiyalar üçün mümkündür.
Nəticə
Əvvəla deyim ki, bu yazı İsmoş adlı bir şəxs üçün yazılmışdır. Lakin sonradan belə ümumi hala salındı. Yazının əsas hissəsini Tim Caswell-in JavaScript üçün yazdığı möhtəşəm məqalalərdən onun icazəsi ilə tərcümə edilərək müəyyən əlavələr edilib. Ona görə yazını “copy-paste” edəndə referans verməyiniz xahiş olunur. Əgər yazının tamamı mənə aid olsa, belə bir xahiş etməzdim. Gələn yazılarda inşallah this
və qapanmalar haqda Tim Caswell-in ayrı bir yazısını tərcümə edərək maraqlı misallar da əlavə etməyə çalışacağam. Hə bir də, əgər heç proqramlaşdırma haqda anlayışınız yoxdursa, onda biraz təməl səviyədə öyrənib sonra bu yazılardan faydalanmaq daha gözəl olar. Amma bilməsəniz də olar. Sağ Salamat!
Referanslar:
JavaScript With Object Graphs
JavaScript: The Good Parts