داستان Prototypal Inheritance در جاوااسکرپیت به زبان خیلی ساده

من خودم شدیدا از خوندن متن های طولانی متنفر هستم و تا حد ممکن سعی میکنم طولانی هم ننویسم، اما احتمالا این متن به دلایل فنی طولانی میشه ولی امیدوارم خوندنش خسته کننده نباشه

صلب مسئولیت

  • تو این متن سعی شده مسئله Prototypal Inheritance در javascript بصورت خیلی ساده و روان بیان کنم، بنابراین ممکنه از گفتن برخی مسائل بصورت فنی تخصصی اجتناب شده باشه و برخی چیزها به بیان خیلی عامیانه گفته شده باشه
  • مطلب خوبی به فارسی پیدا نکردم وگرنه احتمالا منم نمی نوشتم :))
  • قطعا شما سوادتون از من بیشتره :))
  • غلط دیکته ای های بنده رو به بزرگی خودتون ببخشید

خود Inheritance چیه اصلا ؟

خب قطعا اگر قبلا با یکی از زبان های برنامه نویسی شی گرا ( object oriented) کار کرده باشید میدونید که یکی از اصول این مدل برنامه نویسی همین ارث‌بری یا Inheritance هست. به بیان ساده وقتی یک instance object از یک class میسازید و یا زمانی که یک class رو از یک class دیگر extend می کنید، اون object و class جدید تمام methodها و propertyهای کلاسِ مادر رو به ارث می‌برند و میتونن از اونها استفاده کنن، علاوه بر این خود اینها میتونن یکسری متد و خصوصیت جدید برای خودشون داشته باشند و یا method ها و propertyهای ارث برده شده رو برای خودشون override کنند.

حالا Prototype چی میگه ؟

خب javascript ( یا همان بیشعور بزرگ ) چیزی به اسم class نداره/نداشت ( تا قبل از ES6 ) و برای اینکه بدونیم Prototype چیه ، از اینجا شروع میکنیم که :

  • تو javascript برای پیاده کردن class از function ها استفاده میشد
  • فانکشن‌هایی که برای ایجاد یک instance object از اونها از دستور new استفاده میشه، فانکشن‌های سازنده یا constructor functions گفته میشن، به کد زیر دقت کنید:
function myFunc(){ // constructor functions 
   this.myProperty = "My Property ";
 }
 var myObj = new myFunc();
  • همه functionها ( حتی اونایی که هیچ کاری نمیکنن و خالی هستن ) تو javascript خودشون object هستند
  • همه functionها تو javascript بدون اینکه شما براشون چیزی تعریف کنید یا بدونید، بصورت پیشفرض یک property مخفی به اسم prototype دارند ( که یک object برمیگردونه ) مثل کد زیر می تونید بهشون دسترسی پیدا کنید :
function hichi(){
        // I do nothing
}
console.log(typeof hichi.prototype); // object 

شما میتونید methodهای دلخواه خودتون رو به prototype یک فانکشن اضافه کنید:

function myFunc(){ 
      this.myProperty = "My Property "; 
 }
 myFunc.prototype.myMethod = function() {
   console.log('this is my method');
};

و اگر از اون فانکشن یک instance object بسازید، آبجکت جدید ما میتونه به متدهای prototype اون فانکشن مادر دسترسی داشته باشه :

 function Mom(){
          this.momProperty = "My Property ";   
 }  
 Mom.prototype.speak= function() {    
   console.log("I'm speaking");
  }; 
  
 var child= new Mom();
child.speak(); // I'm speaking

دقت کنید در قطعه کد بالا child صرفا از طریق مادرِ خودش یعنی Mom به متد speak دسترسی داره و در واقع speak در child.prototype وجود نداره به عبارتی :

child.hasOwnProperty('speak') === false) 

که تو javascript به این مدل ارث‌بری میگیم Differential Inheritance

خب Object.create چیکار میکنه ؟

این فانکشن هم که از es5 اضافه شده، یک آبجکت خالی برای ما میسازه که به متدها و خصوصیات فانکشن مادرش دسترسی داره به این قطعه کد دقت کنید :

var parent = {
  foo: function() {
    console.log(‘bar’);
   }
};
var child = Object.create( parent );
child.hasOwnProperty(‘foo’); // false
child.foo(); // ‘bar’

بریم سراغ مثال‌های جدی تربه قطعه کد زیر دقت کنید :

function Rectangle( width, height ) {
    this.width = width;
    this.height = height;
}
Rectangle.prototype.area = function() {
    return this.width * this.height;
}; 
var mrect = new Rectangle( 3, 4 );
mrect.area(); // 12

دیدید که چطوری mrect از Rectangle ارث‌بری میکنه، حالا فرض کنیم ما یک فانکشن سازنده دیگه به اسم Square داریم

function Square( length ) {
    this.width = this.height = length;
}

حالا چیکار کنیم که Square از Rectangle ارث‌بری کنه ؟ (دقت کنید Square دیگه یک آبجکت خالی نیست) خیلی ساده است :

Square.prototype = Object.create( Rectangle.prototype );

از این به بعد تمام instanceهایی که از Square ساخته بشن از خود Square ارث می‌برن و چون Square از Rectangle ارث برده، همه اونها به متدها و خصوصیات Rectangle دسترسی خواهند داشت :

var mInstance= new Square( 4 );
mInstance.area(); // 16

خب تقریبا کلیت چیزی که باید میدونستیم همینه

حالا __proto__ ماجراش چیه ؟

ببین شما تو فانکشنِ Parentخصوصیتِ prototype رو دارید، زمانی که بچه به دنیا میاد :) یعنی child از parent ساخته میشه خصوصیت __proto__ در child معادل prototype در Parent میشه با کد توضیح بدم بهتر می فهمید :

function Parent(){
    this.name = "parent";
}
var child = Object.create( Parent.prototype );
console.log( Parent.prototype === child.__proto__ ); // true

یک مثال بهتر :

function Parent(y) {
        this.y = y;
  }
Parent.prototype.x = 10;
Parent.prototype.speak= function (z) {
        return this.x + this.y + z;
  };
var child= new Parent(20);
child.speak(30); // 60
console.log(
  child.__proto__ === Parent.prototype, // true
  child.__proto__.speak=== Parent.prototype.speak, // true
  child.__proto__.speak=== child.speak, // true
  Parent === child.constructor, // true
  Parent=== Parent.prototype.constructor   // true
  );

حالا بیاید این چیزایی که یاد گرفتیم رو مقایسه کنیم با Class Inheritance تو جاوااسکریپت جدید

خب شبیه به بقیه زبان های برنامه نویسی تعریف کلاس و ارث‌بری ازش به شکل زیر قابل انجامه

class Parent{
	constructor() {
	    this.name = "Parent";
	  }
	speak(){
		 console.log(this.name+" speaks!");
	} 
}

class child extends Parent{
 	constructor(name) {
 		super();
     		this.name = name ;
       }
}

var mohsen= new child("mohsen");
mohsen.speak(); // mohsen speaks

اگر نکته ای داشتید خوشحال میشم به مطلب من اضافه کنید

و اینکه اگر توسعه دهنده جاوااسکریپت خوبی هستید کلی موقعیت شغلی هر روز برای شما اینجا هست و یک رویداد خفن هم بزودی برگزار میشه که اینجا می تونید اطلاعات بیشتر رو پیدا کنید
استخدام