ارث بری بین کلاسها (اینفوگرافی)

شی گرایی در جاوا اسکریپت (آموزش کامل به زبان ساده)

اساطیر زبان

برنامه نویسی شی گرا یا OOP (Object-Oriented Programming) یک الگوی برنامه نویسی مبتنی بر مفهوم اشیا است. الگوی برنامه نویسی به معنای سبک کد؛ یعنی نحوه نوشتن و سازماندهی کد.

از اشیا برای مدل سازی (توصیف) جنبه های دنیای واقعی مانند یک کاربر یا یک مورد در لیست کارها و یا حتی ویژگی های انتزاعی تر مانند یک مولفه HTML یا انواع ساختار داده استفاده می کنیم.

 


جاوا اسکریپت

توی این پک فوق العاده، جاوا اسکریپت رو جوری یاد میگیری که تو هیچ کلاس آموزشی یا پک دیگه ای نه دیدی نه شنیدی! بدون هیچ کلاسی، با جاوا اسکریپت اپلیکیشن بزن، پروژه محور یاد بگیر و حسابی پول در بیار! 


 

هر شی دو فاکتور مهم دارد؛ خصوصیات که ویژگی های مرتبط با شی هستند و متدها که رفتار و اعمال شی را نشان می دهند.

شی گرایی به طور کلی: شی گرایی چیست؟ زبانهای‌ برنامه نویسی شیء گرا کدامند؟

بنابراین اشیا شامل داده (خصوصیات) و همچنین کد (متدها) می باشند که می خواهیم آنها را در سیستم مدل سازی کنیم. با استفاده از اشیا همه داده ها و رفتار متناظر را در یک بلوک بزرگ جمع آوری می کنیم.

در OOP بلوک کد اشیا مانند برنامه های کوچک مستقل هستند. اشیا بلوک های سازنده برنامه هستند و با یکدیگر تعامل دارند. تعاملات از طریق رابط عمومی (API) برقرار می شود. این رابط در اصل مجموعه ای از متدهایی است که یک کد خارج از شی با استفاده از آن می تواند با شی ارتباط برقرار کند.

برنامه نویسی شی گرا با هدف سازماندهی کد برای انعطاف پذیری و نگهداری آسانتر توسعه یافته است.

word image 259

سه روش پیاده سازی وراثت نمونه اولیه

1- تابع سازنده

  • از تکنیک ایجاد اشیا از یک تابع استفاده می شود.
  • در اصل اشیای داخلی مانند آرایه ها، مجموعه ها و .. با این روش پیاده سازی می شوند.

2- کلاس های ES6

  • جایگزین مدرن برای ساختار تابع سازنده است.
  • سینتکس “Syntactic sugar” دارد که خواندن، نوشتن و فهم کدها را آسان می کند اما در پشت صحنه کلاس های ES6 دقیقاً مانند توابع سازنده کار می کنند.
  • کلاس های ES6 مانند کلاس های “برنامه نویسی شی گرا کلاسیک” رفتار نمی کنند.

3- ()Object.create

  • ساده ترین و مستقیم ترین روش برای اتصال یک شی به یک نمونه اولیه است.

1-توابع سازنده و عملگر “new”

  • در جاوا اسکریپت (JavaScript) واقعاً تفاوتی بین تابع عادی و تابع سازنده وجود ندارد. آنها در واقع مشابه هستند اما به عنوان یک قرارداد نام توابعی که به عنوان سازنده مورد استفاده قرار گیرند، اغلب با حرف بزرگ شروع می شود.
  • در جاوا اسکریپت همه توابع نیز شی هستند، یعنی می توانند ویژگی ها یا خصوصیاتی داشته باشند. همه آنها یک خاصیت به نام “prototype یا نمونه اولیه” دارند که آن هم یک شی است.
  • با ایجاد یک تابع یک خاصیت به نام نمونه اولیه (Prototype) به طور خودکار برای آن وجود خواهد داشت که در یک شی خالی مقداردهی اولیه می شود.
  • prototype یک خاصیت از شی تابع است. نمونه اولیه اشیای ساخته شده توسط آن تابع می باشد. از آن برای ساخت __proto__  هنگام ساخت شی جدید با عملگر new استفاده می شود.
  • برای اشاره به نمونه اولیه هر شی (در برنامه نویسی) از خاصیت داخلی __proto__  استفاده می شود. یک شی واقعی است که در زنجیره جستجو برای حل متدها از آن استفاده می شود.

instanceof : عملگری است که بررسی می کند آیا خاصیت یا ویژگی prototype سازنده در جایی از زنجیره نمونه اولیه شی ظاهر می شود یا خیر. مقدار بازگشتی آن یک مقدار بولین (TRUE یا FALSE) است.

isPrototypeOf: متدی است که بررسی می کند که آیا یک شی در زنجیره نمونه اولیه شی دیگری وجود دارد یا خیر.

hasOwnProperty: متدی است که نشان می دهد آیا یک شی، خاصیت مشخص شده را به عنوان یکی از خصوصیات خودش دارد یا خیر. یک مقدار بولین برمی گرداند.

const Person = function(name, birthYear){

this.name = name;

this.birthYear = birthYear;

}

const jonas = new Person(‘jonas’, 1990);

console.log(jonas); // { birthYear: 1990, name: “jonas”}

const ayush = new Person(‘ayush’, 1992);

console.log(ayush); // { birthYear: 1992, name: “ayush”}

console.log(ayush instanceof Person); //true

//Prototypes

Person.prototype.calcAge = function(){

console.log(2021 – this.birthYear);

}

jonas.calcAge(); //31

ayush.calcAge(); //29

console.log(ayush.__proto__); // {calcAge: ƒ, constructor: ƒ}

console.log(ayush.__proto__ === Person.prototype); //true

console.log(Person.prototype.isPrototypeOf(jonas)); //true

console.log(Person.prototype.isPrototypeOf(ayush)); //true

console.log(Person.prototype.isPrototypeOf(Person)); //false

Person.prototype.species = ‘Homo sapiens’;

console.log(ayush.species); // Homo sapiens

console.log(ayush.hasOwnProperty(‘name’)) //true

console.log(ayush.hasOwnProperty(‘species’)) //false

console.log(jonas.hasOwnProperty(‘name’)) //true

بریم ببینیم وراثت نمونه اولیه چگونه کار می کند:

word image 260

زنجیره نمونه اولیه

جاوا اسکریپت از یک مدل ارث بری به نام وراثت تفاضلی یا ناهمسان استفاده می کند. یعنی اینکه متدها از والد به فرزند کپی نمی شوند. در عوض فرزندان یک “پیوند نامرئی” به شی والد خود دارند. معمولاً به آن “زنجیره نمونه اولیه یا زنجیره پروتوتایپ” گفته می شود.

word image 261

console.log(jonas.__proto__);
//{ species: “Homo sapiens”, calcAge: f, constructor: f}

console.log(jonas.__proto__.__proto__);
//{ constructor: f, _defineGetter_: f, _defineSetter_: f, hasOwnProperty: f, ….}

console.log(jonas.__proto__.__proto__.___proto__);
//null

console.dir(Person.prototype.constructor);
//constructor property points back at person

const arr = [1,2,3,4,5];
console.log(arr.__proto__); //contains all the built-in array methods
console.log(arr.__proto__ === Array.prototype); //true

console.log(arr.__proto__.__proto__); //all object properties
console.log(arr.__proto__.__proto__.__proto__); //null

const h1 = document.querySelector(“h1”);
console.dir(h1); //object
console.log(x=> x*2); //object

می توانیم متدهای جدید را به این نمونه اولیه اضافه کنیم، سپس همه آرایه ها آن را به ارث خواهند برد.

Array.prototype.unique = function() {
return […new Set(this)];
};

let arr = [1,2,3,2,1,4,5];
console.log(arr.unique()) // [1,2,3,4,5]

2-کلاس های ES6

کلاس ها در جاوا اسکریپت مانند کلاس های سنتی در سایر زبان های برنامه نویسی مانند Java یا C++ کار نمی کنند. کلاس ها در جاوا اسکریپت فقط “syntactic sugar” یا سینتکس ساده و قابل فهم توابع سازنده هستند. در کلاس ها هم مشابه توابع سازنده وراثت نمونه اولیه در پشت صحنه پیاده سازی می شود اما سینتکس آن برای افراد آشنا با سایر زبان های برنامه نویسی منطقی تر و قابل فهم تر می باشد. در واقع اصل همین هدف اساسی اضافه کردن کلاس ها به جاوا اسکریپت بوده است.

//class expression (class are functions behind the cenes)

//const PersonCl = class {}

//class declaration

class PersonCl{

constructor(firstName, birthYear){

this.firstName = firstName;

this.birthYear = birthYear;

}

// Method will be added to .prototype property

calcAge (){

console.log(2020 – this.birthYear)

}

}

const ayush = new PersonCl(‘Ayush’,’1992′);

console.log(ayush); //PersonCl {firstName: “Ayush”, birthYear: “1992”}

ayush.calcAge(); //28

console.log( ayush.__proto__ === PersonCl.prototype ); //true

console.log( ayush.hasOwnProperty(‘firstName’) ); //true

console.log( ayush.hasOwnProperty(‘calcAge’) ); //false

PersonCl.prototype.greet = function(){

console.log(`Hey ${this.firstName}`);

}

ayush.greet(); //Hey Ayush

نکات مهم

  • کلاس ها به هیچ وجه Hoisted نمی شوند. یعنی نمی توان از کلاس ها قبل از تعرف آن ها استفاده کرد.
  • کلاس ها دقیقاً مانند توابع دارای ویژگی first-class citizens هستند، یعنی می توان آنها را در متغیرها یا ساختارهای داده ذخیره کرد و به همین ترتیب می توان آنها را به توابع انتقال و یا از توابع برگشت داد. دلیلش این است که در واقع در نهان، کلاس ها نوع خاصی از توابع هستند.
  • بدنه یک کلاس همیشه در حالت strict mode اجرا می شود. حتی اگر آن را برای کل اسکریپت فعال نکنیم، باز هم همه کدهای کلاس در این حالت اجرا خواهند شد. در حالت strict mode کدها با شرایط سخت گیرانه تری اجرا می شوند.

توابع سازنده، ساختار قدیمی یا منسوخ نیستند. استفاده از آنها صد درصد خوب است. اینجا بیشتر مسئله اولویت شخصی است.

آموزشهای برنامه نویسی رایگان ما در اینجا

Setters و Getters

هر شی در جاوا اسکریپت می تواند ویژگی های Setters و Getters را داشته باشد. به این خصوصیات خاص، خصوصیات ارزیاب گفته می شود در حالیکه به خصوصیات نرمال، خصوصیات داده ای می گویند. Setters و Getters در اصل توابعی هستند که برای اختصاص و بازیابی مقدار یک خاصیت شی استفاده می شوند.

تابع set یک مقدار به خاصیت شی اختصاص می دهد و تابع get مقدار خاصیت شی را بازیابی می کند.

برای اشیا:

const account = {
owner: ‘Ayush’,
movements: [100,50, 300, 40],

// read something as a property
get latest(){
return this.movements.slice(-1).pop();
},

set latest(mov){
this.movements.push(mov);
}
}

console.log(account.latest); //40
account.set = 60;
console.log(account.movements); //[100, 50, 300, 40]

کلاس ها نیز setters و getters دارند و دقیقاً به همان روش کار می کنند. در واقع Getter دقیقاً مانند هر متد معمولی دیگری است که روی نمونه اولیه تنظیم می کنیم. setters و getters برای اعتبار سنجی داده ها نیز بسیار مفید می باشند.

برای کلاس ها:

class PersonCl{
constructor(firstName, birthYear){
this.firstName = firstName;
this.birthYear = birthYear;
}

// Method will be added to .prototype property
get age (){
return 2020 – this.birthYear;
}
}

const ayush = new PersonCl(‘Ayush’,’1992′);
console.log(ayush.age); //28

متدهای استاتیک

برای درک بهتر یک متد استاتیک (ایستا یا static)، متد داخلی ()Array.from را به عنوان یک مثال خوب توضیح می دهیم. متد ()Array.from هر ساختار شبیه آرایه را به یک آرایه واقعی تبدیل می کند.

Array.from(document.querySelectorAll(‘h1’));
//[h1]

متد ()from در اینجا به سازنده Array وصل شده است. بنابراین نمی توانیم متد from را روی Array استفاده کنیم زیرا این متد به یک خاصیت از نمونه اولیه سازنده متصل نیست. بنابراین همه آرایه ها از این متد ارث نمی برند. در واقع برای فراخوانی متدهای ایستا نیازی به ساخت شی نیست و از کلاس فراخوانی می شوند.

[1,2,3].from();
//Uncaught TypeError: [1,2,3].from is not a function

()Number.parseFloat یک متد استاتیک دیگر است و روی سازنده Number (نوع عددی) ایستا است. بنابراین روی اعداد در دسترس نیست، فقط در سازنده آن قابل دسترسی است.

Number.parseFloat(12);
//12

اینها چند نمونه خوب برای درک بهتر متد استاتیک بود. معمولاً از این نوع متدها زمانی استفاده می کنیم که باید به یک سازنده خاص ارتباط داده شود. حالا این کار را برای هر دو تابع سازنده و همچنین کلاس انجام می دهیم.

//تابع سازنده

const Person = function(firstName, birthYear){

this.firstName = firstName;

this.birthYear = birthYear;

}

//پروتوتایپ ها

Person.prototype.calcAge = function(){

console.log(2021 – this.birthYear);

}

//Static متد

Person.hey = function (){

console.log(‘Hey there!’);

console.log(this); //constructor function

}

Person.hey(); //Hey there!

const jonas = new Person(‘jonas’, 1990);

jonas.hey(); //Uncaught TypeError: jonas.hey is not a function

//کلاس

class PersonCl{

constructor(firstName, birthYear){

this.firstName = firstName;

this.birthYear = birthYear;

}

//Instance methods

//Method will be added to .prototype property

calcAge (){

console.log(2020 – this.birthYear)

}

//Static متد

static hey(){

console.log(‘Hey there!’);

}

}

PersonCl.hey(); //Hey there!

const ayush = new PersonCl(‘Ayush’,’1992′);

ayush.hey(); //Uncaught TypeError: ayush.hey is not a function

3-()Object.create

روش سوم استفاده از تابعی به نام ()Object.create است که کاملاً متفاوت از توابع سازنده و کلاس ها کار می کند. در تابع ()Object.create نیز ایده وراثت نمونه اولیه وجود دارد. با این حال ویژگی نمونه اولیه و تابع سازنده و عملگر new  وجود ندارد. بنابراین به جای آن از ()Object.create استفاده می کنیم تا نمونه اولیه یک شی را به صورت دستی روی هر شی دلخواه دیگری تنظیم کنیم.

const PersonProto = {
calcAge (){
console.log(2020 – this.birthYear);
}
}

const ayush = Object.create(PersonProto);
console.log(ayush); //{}
//empty object and in the prototype we have calcAge.

ayush.name = ‘Ayush’;
ayush.birthYear = 1992;
ayush.calcAge(); //28

word image 262

هنگامی که از عملگر new در توابع سازنده یا کلاس استفاده می کنیم، آن به طور خودکار نمونه اولیه نمونه ها به سازنده ها، خاصیت prototype را تنظیم می کند. این به طور خودکار اتفاق می افتد.

از طرف دیگر با استفاده از ()Object.create می توانیم مقدار نمونه اولیه اشیا را به صورت دستی به هر شی دلخواه تنظیم کنیم.

خصوصیات و متدها در یک زنجیره نمونه اولیه درست مانند سازنده ها یا کلاس ها کار می کنند. در حقیقت، زنجیره پروتوتایپ یا نمونه اولیه در اینجا دقیقاً به همان شکل است. تفاوت بزرگ این است که برای رسیدن به یک چیز مشابه به هیچ تابع سازنده و یا خاصیتی از نمونه اولیه نیاز نداریم. در واقع از این روش کمتر برای وراثت نمونه اولیه استفاده می شود.

const PersonProto = {
calcAge (){
console.log(2020 – this.birthYear);
},

init(firstName, birthYear){
this.firstName = firstName;
this.birthYear = birthYear;
}
}

const ayush = Object.create(PersonProto);

console.log(ayush.__proto__ === PersonProto); //true

const anu = Object.create(PersonProto);
anu.init(‘Anu’, 1990);
anu.calcAge(); //30

بهترین زبان برنامه نویسی برای کار و درآمدزایی

ارث بری بین کلاس ها

word image 263

توابع سازنده

const Person = function(firstName, birthYear){

this.firstName = firstName;

this.birthYear = birthYear;

}

Person.prototype.calcAge = function(){

console.log(2021 – this.birthYear);

}

const Student = function(firstName, birthYear, course){

//this.firstName = firstName;

//this.birthYear = birthYear;

Person.call( this,firstName, birthYear);

this.course = course;

}

//Linking prototypes

Student.prototype = Object.create(Person.prototype);

Student.prototype.introduce = function(){

console.log(`My name is ${this.firstName} and I study ${this.course}.`)

}

const mike = new Student(‘Mike’,’1992′,’Computer Science’);

console.log(mike);

//Student {firstName: “Mike”, birthYear: “1992”, course: “Computer Science”}

mike.introduce();

//My name is Mike and I study Computer Science.

mike.calcAge(); //29

console.log(mike.__proto__);

console.log(mike.__proto__.__proto__);

console.dir(Student.prototype.constructor); // ƒ Person(firstName, birthYear)

//pointing to Person, and the reason for that is that we set the prototype property of the student using Object.create.

//We need to fix this, just say student.prototype.constructor and set it to student.

Student.prototype.constructor = Student;

console.dir(Student.prototype.constructor); //ƒ Student(firstName, birthYear, course)

console.log(mike instanceof Student); //true

console.log(mike instanceof Person); //true

console.log(mike instanceof Object); //true

word image 264

word image 265

word image 266

کلاس هایES6

class PersonCl{

constructor(firstName, birthYear){

this.firstName = firstName;

this.birthYear = birthYear;

}

// Method will be added to .prototype property

calcAge (){

console.log(2021 – this.birthYear)

}

}

class StudentCl extends PersonCl {

constructor(firstName, birthYear, course){

//Always needs to happen first!

super(firstName, birthYear); //constrcutor function of parent class

this.course = course;

}

introduce() {

console.log(`My name is ${this.firstName} and I study ${this.course}.`)

}

//override parent class method

calcAge() {

console.log(`I am ${2021 – this.birthYear} years old.`);

}

}

const martha = new StudentCl(‘Martha Jones’, 2012, ‘Computer Science’);

martha.introduce(); //My name is Martha Jones and I study Computer Science.

martha.calcAge();

//9 – if only parent calcAge is present

//I am 9 years old. – if child overrides parent class with same name

console.log(martha);

()Object.create

const PersonProto = {

calcAge (){

console.log(2020 – this.birthYear)

},

init(firstName, birthYear){

this.firstName = firstName;

this.birthYear = birthYear;

}

}

const ayush = Object.create(PersonProto);

//Linking prototypes

const StudentProto = Object.create(PersonProto);

StudentProto.init = function(firstName, birthYear, course){

PersonProto.init.call(this,firstName, birthYear);

this.course = course;

}

StudentProto.introduce = function(){

console.log(`My name is ${this.firstName} and I study ${this.course}.`)

}

const jay = Object.create(StudentProto);

jay.init(‘Jay’,2010, ‘Computer Science’);

jay.introduce(); //My name is Jay and I study Computer Science.

jay.calcAge(); //10

console.log(jay);

word image 267

در این روش حتی نگران سازنده ها و خصوصیات نمونه اولیه و همچنین عملگر new هم نیستیم. فقط اشیا به یکدیگر لینک داده شده اند. همین! واقعاً ساده و زیبا است.

در این روش با ()Object.create کلاس ها ساختگی نیست. همه کاری که انجام می دهیم این است که به سادگی اشیا را بهم وصل کنیم، جایی که بعضی از اشیا بعدا به عنوان نمونه اولیه سایر اشیا عمل می کنند. کلاس های ES6 و توابع سازنده در دنیای واقعی بیشتر استفاده می شوند.

word image 268

حتما دانلود کنید: آموزش صفر تا صد جاوا اسکریپت (رایگان)

تفاوت پک های حرفه ای ما با آموزشهای رایگان: بطور خلاصه از زمین تا آسمان! 1-پکها، جدیدترین نسخه نرم افزارها را آموزش می دهند با قابلیت های بسیار بیشتر. 2-پکها توسط متخصص آن نرم افزار، به صورت کاملا پروژه محور و با حل چالش هایی که در مسیر کار عملی و حرفه ای با آن روبرو می شوید تهیه شده اند و بعد از استفاده، کاملا برای بازار کار آماده اید! 3- متد این پکها کاملا کار شده و تا ماهها، در ذهن تان ماندگارند و یادگیری بسیار سریعتر و کاملتری خواهید داشت. آموزشهای رایگان فقط دستورات نرم افزارها را (آنهم ناقص) بیان می کنند و تازه برای ورود به بازار باید ماهها تجربه عملی هم کسب کنید !!

turned_in

چرب زبان

با این اپلیکیشن ساده، هر زبانی رو فقط با 5 دقیقه در روز، توی 80 روز مثل بلبل حرف بزن! بهترین متد روز، تقویت حافظه، آموزش تصویری. یادگیری زبان کلید یادگیری هر مهارتی در قرن 21 !


حتما بخوانید!

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

این فیلد را پر کنید
این فیلد را پر کنید
لطفاً یک نشانی ایمیل معتبر بنویسید.

فهرست