Obyekt-Yönümlü JavaScript

Ilkin Guluzada
Frontend Azerbaijan

--

Bu məqalədə mən sizə JavaScript-də Obyekt Yönümlü Proqramlaşdırma haqqında ümumi məlumat verəcəm. Əlbəttə ki, yazı sizə bütün mövzular haqqında dərin məlumat verə bilməyəcək, lakin OOP-də nələr baş verdiyi haqqında sadə ideya verəcək.

Mövzular:

  • OOP nədir?
  • JS-də Obyektlər
  • Prototip Varisliyi
  • Modullar
  • Kapsülləşdirmə (Encapsulation)

1. OOP Nədir?

OOP obyektlərdən qurulmuş proqramlaşdırma paradiqmasıdır. Başlanğıc olaraq, mən sizə OOP haqqında sadə anlayış vermək istəyirəm. OOP əsasən, real həyatda mövcud olan əşyaların (obyektlərin) proqramlaşdırmada modelləşdirilməsi, onları yenidən istifadəyə yararlı hala gətirilməsi, kodumuzun orqanizasiyası & səliqələliyi və çətin proqramların onlar üzərində kontrolun itirilməməsi şərti ilə qurulması üçün istifadə olunur. OOP ilə individual obyektləri proqramımız digər hissələrinə təsiri olmadan dəyişdirə bilirik və bu da OOP ilə yazılan proqramların yenilənməsi və düzəliş edilməsini asanlaşdırır. OOP-nin kök saldığı proqramlaşdırma dillərində biri də JavaScriptdir.

JS-də OOP

JS obyekt yönümlü dil olmasına baxmayaraq, insanlar onun bu xüsusiyyətindən istifadə etmir. JS-də 5 sadə data tipi mövcuddur (Undefined, Null, Boolean, String, Number), və onların ‘boxed’ versiyaları da var, hansı ki onlar da obyekt sayılır.

var a = 1;
var b = new Number(1);
var c = a+b;
typeof(a); //‘number’ qaytarır
typeof(b); //‘object’ qaytarır
typeof(c); //‘number’ qaytarır

2. JS-də Obyektlər

Obyekt, uyğun dataların və funksiyaların kolleksiyasından ibarət data strukturdur. Gəlin real həyatda mövcud olan bir obyekt fikirləşək: maşın. Maşın xüsusiyyətləri (rəng, qiymət, brend) və funksionallıqları (sürmək, sağa və ya sola dönmək, dayanmaq) olan bir obyektdir. İndi isə onu proqrammatik bir obyektə çevirək.

var mashin = {
reng: 'qara',
qiymet: $50.000,
brend: 'BMW 5 series',
sur: function() {
//kod burada
},
don: function(direction) {
//kod burada
},
dayan: function() {
//kod burada
},
};
mashin.brend; //'BMW 5 series' qaytarir
mashin.don(yonu); //funksionallığı işlədir
mashin.reng; //'qara' qaytarir

Bu nümunədə, maşın, 3 xüsusiyyəti (rəng, qiymət, brend) və 3 funksionallığı (sürmək, sağa və ya sola dönmək, dayanmaq ) olan bir obyektdir. Obyektin xüsusiyyətlərinə (properties) və funksionallıqlarına (methods) nöqtə nişanı (dot notation) ilə çata bilərsiniz: obyektAdi.xususiyyet; obyektAdi.funksiya(arqument)

Obyekt xüsusiyyətlərinə həmiçini mörtərizə nişanı (bracket notation) ilə də çata bilirik. Bu zaman biz onlara əlaqələndirilmiş massiv kimi davranırıq: obyektAdi['xüsusiyyət'];

JavaScript dinamik dil olduğuna görə biz obyetklərə çox asan xüsusiyyət və funksionallıq əlavə edə bilirik. Növbəti kod maşın obyektinə ‘il’ xüsusiyyəti və ‘drift’ metodu əlavə edəcək: mashin.il= ‘2018’; mashin.drift= function(){ //kod burada };

Növbəti bilməli olduğumuz mövzu this açar sözüdür. this açar sözü bizə hal-hazırda içərisində kod yazdığımız obyekti qaytarır. Nümunəyə baxaq:

var insan = {
ad: 'Ilkin',
salamDe: function() {
alert('Salam, ' + this.ad + '.');
}
}

Bu nümunədə, 4-cü sətirdəki this.ad, insan obyektinin ad xüsusiyyətini qaytarır.

Artıq biz, uğurla JavaScript Obyektini yaratdıq. Obyektlər klass olmadıqlarına görə, biz bir obyektdən bir neçə fərd (instance) yarada bilmirik. Bəs biz Əlövsət adlı insan fərdi yaratmaq istəsək neynəməliyik? Bu halda insan obyektindən eynisini bir neçə dəfə yaratmaq lazım olur, lakin bu da proqram performansına görə yaxşı metod deyil. Onun yerinə biz obyekti konstruktor funksiyası (Obyekt Konstruktoru kimi də bilinir) ilə yaradırıq və həmin obyektin fərdlərini yarada bilirik. Nümunə:

var Insan = function(ad){
this.ad = ad;
this.salamDe = function() {
alert('Salam, ' + this.ad + '.');
};
}
var elovset = new Insan('Elovset');
elovset.salamDe(); //'Salam, Elovset.' alert edir.
var ilkin = new Insan('Ilkin');
ilkin.salamDe(); //'Salam, Ilkin.' alert edir.

Lakin bu yolun yaddaş ilə bağlı mənfi cəhəti var. İnsan obyektinin fərdini yaradanda, hər fərd ayrılıqda öz konstruktor funksiyasını yaradır hansı ki, hərəsini öz xüsusiyyət və fuksionallıqları var. Bu da yaddaşda boşuna əlavə yer tutmuş olur.

Bütün fərdlər yaddaşda yer tutur

Bu problemə görə, prototiplər mövzusunu öyrənəciyik.

3. Prototiplər

JavaScriptin klass üçün birbaşa dəstəyi olmadığı kimi (ES6-da var), onun varislik konsepsiyası da yoxdur. Onun yerinə eyni funksionallığı olan prototip istifadə edəciyik. Prototip varisliyinin, klass varisliyindən nəyə görə üstün olduğunu özünüz görəcəksiniz. Prototiplər də obyekt olduqlarına görə, onların da prototipləri ola bilər. Bu konsepsiyanın müsbət cəhəti, prototipə funksiyalar əlavə etdikdən sonra, hər bir fərd bu funksiyadan istifadə edir (yenisini yaratmır) və yaddaşda boşuna yer tutmur. Prototiplərə funksiyaları aşağıdakı kimi əlavə edə bilərik.

var Insan = function(ad){
this.ad = ad;
}
Insan.prototype.salamDe = function(){ console.log('Salam, ' + this.ad); }var elovset = new Insan('Elovset');
elovset.salamDe(); //'Salam, Elovset' konsola yazılır

Prototipə konstruktor funksiyasını əlavə etdikdən sonra, prototip konstruktor funksiyasının obyekti olur və ondan yaranan bütün fərdlərə _proto_ xüsusiyyəti vasitəsi ilə paylanır.

Yalnız Prototip Obyekti yaddaşda yer tutur, bütün fərdlər yox

Nümunəyə baxaq:

//Boş konstruktor funksiyası yaradırıq
var Insan = function(){
}
Insan.prototype.ad= 'Ilkin';
Insan.prototype.adlandir = function(ad){this.ad= ad;}
var elovset = new Insan();elovset._proto_; //Prototip obyektini qaytarır
elovset.ad; //'Ilkin' qaytarır
elovset.adlandir('Elovset');
elovset.ad; //'Elovset' qaytarır
var kichikxanim = new Insan();
kichikxanim.ad; //'Ilkin' qaytarır
//prototipə yeni xüsusiyyət və metodların əlavə olunması
Insan.prototype.soyad= 'Guluzada';
Insan.prototype.salamDe= function(){alert('Salam, ' + this.ad)};
elovset.surname; //'Guluzada' qaytarır
elovset.salamDe(); //'Salam, Elovset' alert olur

Nümunədən də göründüyü kimi, fərdlərin xüsiyyətlərini dəyişsək də prototipin xüsusiyyətləri olduğu kimi qalır. Həmçinin biz, prototipə xüsusiyyət və metod əlavə edə bilirik və əlavə etdiklərimiz bütün fərdlərdən əlçatan olur. Əlavə olaraq, əgər biz prototipdən hansısa xüsusiyyət və ya funksionallıq dəyişsək bu bütün fərdlərdə dəyişmiş olur.

4. Modullar

Modullar bir proqramın müxtəlif hissələridir, hansı ki hər bir hissə ayrılıqda fərqli funksiyanı yerinə yetirir. Məsələn, maşın. Təkərlər, qapılar, qaz pedalı, rol və s. bir maşının müxtəlif hissələridir və hamısı birləşərək bütöv maşını əmələ gətirir. Modullar demək olar ki, bütün ciddi JavaScript proqramlarında istifadə olunur və bir neçə üstünlükləri vardır: Yenidən istifadəyə yaralıdır, dəyişikliklər və yeniliklər asanlıqla inteqrasiya oluna bilir və “Namespacing” xüsusiyyəti vardır. Klasslar və varislik kimi, modullar da JavScriptdə rəsmi olaraq dəstəklənmir, lakin modulları istifadə etmək üçün müxtəlif metodlar mövcuddur. Nümunəyə baxaq:

  • Modul “Pattern”
(function () {  // "Closure Scope"-dəki bütün dəyişkənlər "private"-dir
var ad = 'Elovset'
var salamDe = function(){
return 'Salam, ' + ad;
}
console.log(salamDe());}());// ‘Salam, Elovset’

Qlobal “scope”-dakı dəyişkənlər və metodları fərqləndirmək üçün biz “anonymous closure”-dan istifadə edirik. (function(){ //some code }()) içərisindəki bütün dəyişkənlər “closure scope”-a aiddir, Qlobal “scope”-a yox. Bu qlobal “scope”-dakı dəyişkən və metod adlarının qarışmasına və kodumuzu strukturlu yazmağa kömək edir. Bu metod digər dillərdəki (Java, C#, Python) klass konsepsiyasını demək olar ki əvəzləyə bilər.

  • Tək Obyekt (Obyekt Literal)
var menimModulum = {};menimModulum.ad= 'Ilkin';
menimModulum.salamDe= function(){
return 'Salam, ' + this.ad;
};
var salam = menimModulum.salamDe();

Bu metod problemə sadə obyekt yanaşmasıdır. Obyektdəki xüsusiyyətlərin hamısı dəyişkən olduğuna görə, qlobal “scope”-dakı dəyişkəni obyektin içindəki dəyişkələr ilə fərqləndirə bilərik.

Yaxşı olar ki, “namespace”-ni yaratmazdan əvvəl onun əvvəlcədən mövcud olub olmadığını yoxlayaq: var menimModulum = menimModulum || {}; . Bu kodda, əvvəlcə belə bir modulun olduğuna baxırıq, varsa onu götürürük, yoxdursa yenisini yaradırıq.

  • CommonJS

CommonJS modulu əsasən Javascriptdəki modulları eksport və import eləmək üçün istifadə olunur və bu zaman həmin modulları proqramın istənilən yerində istifadə etmək mümkün olur. Daha çox məlumatı buradan ala bilərsiniz. Nümunə kod ilə modulun import və eksportuna baxaq.

//JS faylının içərisi
function menimModulum() {
this.salamDe = function() {
return 'Salam!';
}
this.sagolDe= function() {
return 'Sagol!';
}
}
//Burada modulu eksport edirik
module.exports = menimModulum;
//Başqa JS faylı
//Burada modulu import edirik
var menimModulum = require('menimModulum');
var ferd = new menimModulum();
ferd.salamDe(); //'Salam!' qaytarır
ferd.sagolDe(); //'Sagol!' qaytarır

5. Kapsülləşdirmə (Encapsulation)

Kapsülləşdirmə obyekt-yönümlü proqramlaşdırmanın əsas konsepsiyalardından biridir. Bu konsepsiya, data və metodların vahid sahədə toplanması ideyasını təsvir edir. Daha sadə desək, bəzi datalarımızı obyekti çölü üçün gizlətməyimizi təmin edir. Yenə də, JavaScript, rəsmi olaraq private, public açar sözlərini dəstəkləmir (yeni versiyada dəstəklənir), lakin eyni funkionallığı müxtəlif yollarla əldə edə bilərik. Biz həmişə klass xüsusiyyətlərini this açar sözü ilə yaradırıq hansı ki, bu həmin xüsusiyyətin “public” olmasına gətirib çıxardır. Əgər həmin xüsusiyyətin “private” olmağını istəyiriksə, sadəcə olaraq dəyişəni this olmadan, var açar sözü iləelan etməliyik.

var Insan = function(adU, soyadU){  //Public xüsusiyyət
this.ad = adU;
//Private xüsusiyyət
var soyad = soyadU;

//Private xüsusiyyəti əlçatan edirik
this.soyadiQaytar = function()
{
return soyad;
}
}
var elovset = new Insan('Elovset', 'Qelbiyuva');elovset.ad; //'Elovset' qaytarır
elovset.soyad; //undefined qaytarır
elovset.soyadiQaytar(); //'Qelbiyuva' qaytarır

Bu funksionallıq üçü başqa metodda mövcuddur. Məsələn:Revealed Module Pattern

var Insan = (function(){ 

//Private xüsusiyyət
var soyad = 'Qelbiyuva';

return{
//Public xüsusiyyət
ad: 'Elovset',

salamDe: function(){
console.log('S, ' + this.name);
}
}
})();
person.soyad; //undefined qaytarır
person.ad; //'Elovset' qaytarır
person.salamDe(); //'Salam, Elovset' konsola yazılır

Xülasə

Bugünki məqalədə, ilkin olaraq ümumi OOP paradiqması və onun JavaScriptə tətbiqi haqqında danışdıq. Növbəti, JavaScriptdə obyekti və ondan yeni fərdləri necə yaratmaq lazım olduğuna baxdıq. Daha sonra, Konstruktor Funksiyala, varislik üçün Prototipləşdirməyə və Modullar, onların tətbiqinə baxdıq. Sonda, kapsülləşdirmə və onun işlənmə yerlərini müzakirə etdik. Bu konsepsiyalar, JavaScriptin ES6-dan əvvəlki versiyalar üçün nəzərdə tutulub. ES6 artıq bəzi konsepsiyaları rəsmi dəstəklədiyinə görə daha asan yolla istədəyimizə çata bilirik. Bu metodların bir çoxu brauzerlər tərəfindən tanınmadığına görə yuxarıda danışdığımız konsepsiyalar hal-hazırda da aktualdır. Növbəti həftələrin birində isə >ES6-da bu konsepsiyalar necə işləndiyi haqqında məqalə yazmağı planlaşdırıram.

Daha çox öyrənmək üçün resurslar:

#1: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#2: https://www.udacity.com/course/object-oriented-javascript--ud711#3: https://www.packtpub.com/web-development/object-oriented-javascript#4: http://shop.oreilly.com/product/9780596806767.do

Ümid edirəm ki, bu yazıda nələrsə öyrənə bildiniz.

Daha çoxu üçün bəyənib paylaşın! :)

Qeyd* Bəzi terminlərin qarşılığı olmadığına görə ingilisə yazmışam və bəzilərini özümdən tərcümə etmişəm. Qarşılığını bildiyiniz terminləri şəxsi mesaj olaraq göndərə bilərsiniz.

Əlaqə: contact@ilkin-guluzada.com

--

--