طرح‌چه

Prototype در جاوااسکریپت چیست؟

۲۶ تیر ۱۴۰۴

Prototype در جاوااسکریپت چیست؟
بررسی مفهوم prototype و کاربرد های آن در جاوااسکریپت

با وجود اینکه اکثر زبان های مشهور دنیا class-based هستن اما به واسطه جاوااسکریپت سطح گسترده ای از دنیای برنامه نویسی رو زبان prototype-based تشکیل می‌دهند. البته ذکر این مطلب نیز قابل توجه هست که بعد از نسخه ECMAScript 2015 (ES6) شما میتونید بدون دانشی از مفهوم prototype، از جاواسکریپت به شکل یک زبان شئ گرا استفاده کنید و عملا فرقی با زبان های دیگر در این زمینه احساس نکنید.

با وجود پیاده سازی کلاس ها در جاوااسکریپت، این زبان همچنان در اصل یک زبان prototype-based هست و پیاده سازی class بر بستر ساختار قدیمی جاوااسکریپت انجام شده.

اما Prototype چیست؟

هر شیء در جاوااسکریپت هنگام ایجاد، به شیء دیگری به نام prototype وصل می‌شود. این پیوند درواقع یک «اشاره‌گر» (reference) است که مسیری برای جست‌وجوی ویژگی‌ها(پراپرتی ها یا متد ها) فراهم می‌کند. اگر شیء فعلی ویژگی «x» را نداشته باشد، موتور جاوااسکریپت در prototype آن به دنبال «x» می‌گردد و این جست‌وجو آن‌قدر ادامه می‌یابد تا به انتهای زنجیره برسد.

نکته: این ساختار را «زنجیرهٔ نمونه‌اولیه» یا prototype chain می‌نامیم.

بیاید اول درک کنیم چرا اصلا نیاز به مفهومی مثل prototype داریم. فرض کنید میخواهیم یک شئ با چند تابع داشته باشیم. مثل:

const blackBird = {
  color: 'black',
  fly: function() { console.log('flying...') },
}

const whiteBird = {
  color: 'black',
  fly: function() { console.log('flying...') },
}

const blueBird = {
  color: 'black',
  fly: function() { console.log('flying...') },
}

blackBird.fly();

در کد بالا ما سه شئ پرنده داریم که فقط رنگ آن ها با هم متفاوت است اما با این پیاده سازی عملا 3 تابع تکراری در حافظه ایجاد شده. در اینجا است که با بجای تعریف چند باره یک تابع می‌توانیم یک Prototype(نمونه اولیه) بسازیم و پیاده سازی را به شکل زیر انجام دهیم:

function Bird(color) {
  this.color = color;
}

Bird.prototype.fly = function() {
  console.log('flying...');
};

const blackBird = new Bird('black');
const whiteBird = new Bird('white');
const blueBird = new Bird('blue');

blackBird.fly(); // logs "flying..."

بنابراین یکی از علت های استفاده از Prototype کاهش تکرار و مصرف بهینه از حافظه است. علاوه بر این، ابزار Prototype امکانات گسترده‌ای برای کدنویسی و پیاده‌سازی در اختیار ما قرار می‌دهد که در ادامه یک مورد آن را بررسی می‌کنیم.

چگونه متد های زنجیره ی بالاتر را بازنویسی(override) کنیم؟

ابجکت تعریف شده زیر بطور پیش فرض در زنجیره prototype خود شئ Object را دارد که در آن متد toString از قبل پیاده سازی شده:

const myObject = {};
console.log(myObject.toString()); // logs "[object Object]"

حالا با دو روش می‌توانیم این رفتار را عوض کنیم:

1. عوض کردن پیاده سازی prototype زنجیره بالاتر

Object.prototype.toString = function() {
  return 'Tarhche';
};

const myObject = {};
console.log(myObject.toString()); // logs "Tarhche"

2. عوض کردن پیاده سازی تنها در خود ابجکت

در نمونه ی زیر به دلیل وجود متد toString در خود شئ، موتور جاواسکریپت به سراغ زنجیره های بالاتر نمی‌رود.

const myObject = {};

myObject.toString = function() {
  return 'Tarhche';
};

console.log(myObject.toString()); // logs "Tarhche"
const anotherObject = {};
console.log(anotherObject.toString()); // logs "[object Object]"

بنابراین با استفاده از همین مکانیزم می‌توان به‌صورت سراسری (global) رفتار المان‌های پیش‌فرض جاوااسکریپت مانند Date، Array یا Math را با تغییر متدها یا مقادیر Prototype آن‌ها دستکاری کرد که این تغییر بر تمام نمونه های ساخته شده از آن ها اعمال می‌شود.

دیدگاه ها