منبع این مقاله : https://sabzlearn.ir/blog/prototype-in-javascript/
prototype در جاوا اسکریپت که به عنوان نمونه اولیه نیز از آن یاد میشود راهی است که اشیاء با استفاده از آن به اشتراکگذاری و به ارث بردن خواص از یکدیگر میپردازند. اگر آموزش جاوا اسکریپت را طی کرده باشید احتمالا میدانید که هر شی در جاوا اسکریپت دارای نوعی نمونه اولیه یا همان prototype است که در اصل ارجاع به یک شیئی دیگر محسوب میشود.
هنگامیکه سعی میکنید به ویژگی یا متد روی شی دسترسی پیدا کنید، جاوا اسکریپت ابتدا آن را در آن شی جستجو میکند؛ اگر آن را پیدا نکرد، نمونه اولیه شی را بررسی کرده و این روند زنجیره نمونه اولیه تا زمانی که ویژگی یا متد پیدا شود یا به انتهای زنجیره برسد، ادامه مییابد.
در مطلب پیش رو از مجله سبزلرن قصد داریم که اطلاعاتی کامل و مفید در رابطه با prototype در جاوا اسکریپت ارائه کنیم.
📷
قبل از پرداختن به مفهوم prototype در زبان برنامهنویسی جاوا اسکریپت، مهم است که به دو مبحث زیر در این زبان تا حدودی مسلط باشیم:
در جاوا اسکریپت میتوانید با استفاده از نوع خاصی از تابع به نام تابع سازنده شی، اشیاء ایجاد کنید. بیایید این فرآیند را با استفاده از مثالی ساده بررسی کنیم:
// Define a constructor function function Person() { this.name = 'John'; this.age = 23; } // Create objects using the constructor function const person1 = new Person(); const person2 = new Person();
تشریح کد بالا به صورت زیر است:
در مثال بالا، تابع Person به عنوان نوعی تابع سازنده شی عمل میکند. این تابع برای ایجاد اشیاء با خصوصیات خاص استفاده خواهد شد.
function Person()
در داخل تابع سازنده، کلمه this در جاوا اسکریپت به نمونهای از شی در حال ایجاد اشاره دارد. در اینجا، ویژگی name شی را روی John قرار میدهیم. به طور مشابه، ویژگی age شی را برابر با 23 قرار خواهیم داد.
this.name = 'John'; this.age = 23;
در خط بعدی از کد بالا شی جدید person1 با استفاده از سازنده Person ایجاد میشود. کلمه کلیدی new در اینجا بسیار مهم است زیرا نمونه جدیدی از شی را ایجاد میکند. به طور مشابه، یک شی دیگر person2 با استفاده از همان تابع سازنده Person ایجاد میشود.
const person1 = new Person(); const person2 = new Person();
تابع سازنده شی نوعی طرح اولیه برای ایجاد اشیاء با ویژگیهای خاص است و در آن کلمه کلیدی new برای نمونهسازی اشیاء از سازنده استفاده میشود. درک این اصول اولیه قبل از عمیقتر شدن در prototype در جاوا اسکریپت بسیار مهم است.
📷
به بیانی ساده جاوا اسکریپت نوعی زبان مبتنی بر نمونه اولیه است و درک شی نمونه اولیه برای برنامه نویسان جاوا اسکریپت بسیار مهم است. این مفهوم حول ویژگی نمونه اولیه میچرخد که به طور خودکار برای توابع در جاوا اسکریپت ایجاد میشود. بیایید این را از طریق مثالی بررسی کنیم:
function Point2D(x, y) { this.x = x; this.y = y; }
در کد بالا هنگامیکه تابع Point2D اعلام میشود، نوعی ویژگی پیشفرض به نام prototype به طور خودکار برای آن ایجاد خواهد شد. در جاوا اسکریپت، تابع نیز نوعی شی است و ویژگی prototype تابع حاوی ویژگی سازنده یا constructor است. در این مثال، Point2D.prototype.constructo روی Point2D طبق کد زیر تنظیم میشود.
Point2D.prototype.move = function(dx, dy) { this.x += dx; this.y += dy; };
اکنون، وقتی از کلمه کلیدی new با تابع Point2 برای ایجاد شی استفاده میکنید، شی جدید ایجاد شده تمام ویژگیهای Point2D.prototype را به ارث میبرد.
برای نشان دادن این موضوع، اجازه دهید متدی به نام move را به Point2D.prototype اضافه کنیم:
Point2D.prototype.move = function(dx, dy) { this.x += dx; this.y += dy; };
حال، اگر یک نمونه از Point2D با استفاده از Point2D(1، 2) جدید ایجاد کنیم، مانند:
var p1 = new Point2D(1, 2);
سپس میتوانیم متد move را در این نمونه فراخوانی کنیم:
p1.move(3, 4);
پس از این عملیات: p1.x برابر ۴ و p1.y برابر ۶ خواهد شد. این نشان میدهد که Point2D.prototype نمونه اولیه شی یا نمونه اولیه شی p1 و همچنین نمونه اولیه هر شی دیگری است.
📷
شما این قابلیت را دارید که ویژگیهای بیشتری را به شی Point2D.prototype اضافه کنید. الگویی متداول این است که متدها را در Point2D.prototype اعلام کنیم، در حالی که سایر خصوصیات در تابع سازنده اعلام میشوند. این الگوی مبتنی بر نمونه اولیه به توابع تعریف شده توسط کاربر محدود نمیشود. همچنین برای اشیاء داخلی در جاوا اسکریپت اعمال میشود؛ مانند مثال زیر:
📷
اشیاء ایجاد شده با استفاده از اشیاء داخلی مانند Date و RegExp نیز از الگوی مشابهی پیروی میکنند. توجه به این نکته مهم است که Object.prototype توسط همه اشیا به ارث میرسد و هیچ نمونه اولیهای ندارد (نمونه اولیه آن null است).
📷
برای درک بهتر نحوه عملکرد prototype در جاوا اسکریپت مثال دیگری را بررسی میکنیم. اساساً در جاوا اسکریپت هر تابع و شی ذاتاً دارای خاصیتی به نام نمونه اولیه است که مثال زیر بیانگر این هدف است.
function Person() { this.name = 'John'; this.age = 23; } const person = new Person(); // Checking the value of the prototype property console.log(Person.prototype); // Output: { ... }
خط اول از کد بالا تابع سازنده به نام Person را تعریف میکند. توابع سازنده برای ایجاد اشیاء با ویژگیهای خاص استفاده میشود.
function Person()
در سازنده Person، کلمه کلیدی this به نمونهای از شی در حال ایجاد اشاره دارد. در اینجا، ویژگی name شی را روی John قرار میدهیم. به طور مشابه، ویژگی age شیء روی 23 تنظیم شده است.
this.name = 'John'; this.age = 23;
در نهایت خط بعدی با استفاده از سازنده Person شی جدید person را ایجاد میکند. کلمه کلیدی new در اینجا بسیار مهم است زیرا نمونهای از شی را ایجاد میکند.
const person = new Person();
ویژگی prototype در جاوا اسکریپت در هر تابع و شی ذاتی است. این نمونه اولیه همانطور که گفتیم به عنوان نوعی طرح برای ایجاد اشیا عمل میکند و میتواند برای گسترش تابعها با افزودن ویژگیها و متدهایی که در بین تمام نمونههای ایجاد شده از تابع سازنده به اشتراک گذاشته میشود، استفاده شود.
📷
زنجیره سازی نمونه اولیه در جاوا اسکریپت (prototype chain) مکانیزمی است که به اشیا اجازه میدهد تا ویژگیها و متدها را از نمونههای اولیه خود به ارث ببرند. هنگامیکه سعی میکنید به نوعی ویژگی (مثلاً ویژگی به نام p) روی شی (obj) دسترسی داشته باشید، موتور جاوا اسکریپت آن ویژگی را در obj جستجو میکند. اگر آن را پیدا نکرد، جستجو را در نمونه اولیه obj ادامه میدهد و این روند تا زمانی که به نمونه اولیه نهایی یعنی Object.prototype برسد، تکرار میشود. اگر بعد از این جستجو هنوز ویژگی پیدا نشد، نتیجه کار تعریف نشده است. مثال زیر برای درک این مفهوم اهمیت زیادی دارد:
var obj1 = { a: 1, b: 2 }; var obj2 = Object.create(obj1); obj2.a = 2; console.log(obj2.a); // Output: 2 console.log(obj2.b); // Output: 2 console.log(obj2.c); // Output: undefined
در مثال بالا obj1 نوعی شی با ویژگیهای a و b است.
var obj1 = { a: 1, b: 2 };
وقتی obj2 با استفاده از Object.create(obj1) ایجاد میکنیم، در حال ایجاد نوعی زنجیره اولیه هستیم. این بدان معنی است که obj1 به نمونه اولیه obj2 تبدیل میشود.
var obj2 = Object.create(obj1); obj2.a = 2;
بنابراین، وقتی به obj2.a دسترسی پیدا میکنیم، جاوا اسکریپت آن را مستقیماً در obj2 پیدا میکند و مقدار 2 را برمیگرداند. برای obj2.b، مستقیماً در obj2 وجود ندارد اما از آنجایی که obj2 از obj1 به ارث میبرد، موتور جاوا اسکریپت در زنجیره نمونه اولیه جستجو کرده و ویژگی را در obj1 پیدا میکند و مقدار 2 را برمیگرداند.
با این حال، برای obj2.c، obj2 و نمونه اولیه آن یعنی obj1 دارای ویژگی به نام c نیستند، بنابراین نتیجه undefined است. این مکانیزم زنجیره اولیه امکان جستجوی کارآمد اشیا را فراهم میکند و قابلیت استفاده مجدد کد را با به اشتراک گذاشتن ویژگیها و متدها از طریق زنجیره prototype در جاوا اسکریپت ارتقا میدهد.
📷
در ES2015 (همچنین به عنوان جاوا اسکریپت ES6 شناخته میشود) و نسخههای بعدی جاوا اسکریپت، کلمه کلیدی class معرفی شد که نحوی آشناتر برای توسعهدهندگانی که با رویکرد برنامهنویسی شیءگرا (OOP) هستند، ارائه میکند.
با این حال، درک این نکته ضروری است که در پشتصحنه، کلاسهای جاوا اسکریپت همچنان با نمونههای اولیه کار میکنند، مشابه متدهایی که قبلاً توضیح داده شد. مثال زیر برای درک این نکته مهم است:
class Rectangle { constructor(height, width) { this.height = height; this.width = width; } get area() { return this.calcArea(); } calcArea() { return this.height * this.width; } } const square = new Rectangle(10, 10); console.log(square.area); // Output: 100
در مثال بالا کلاسی به نام Rectangle تعریف میکنیم. همچنین در کد فوق متد سازنده نوعی متد خاص است که با ایجاد شی جدید از این کلاس فراخوانی میشود. همچنین کلمه کلیدی this ویژگی height و width شی را مقداردهی اولیه میکند.
class Rectangle { constructor(height, width) { this.height = height; this.width = width; }
get area نوعی متد دریافت کننده است که به ما امکان میدهد به ویژگی area شی Rectangle دسترسی پیدا کنیم. این رویکرد راهی راحتتر برای محاسبه مساحت با فراخوانی روش calcArea است.
get area() { return this.calcArea(); }
متد calcArea نوعی متد منظم است که مساحت مستطیل را بر اساس ارتفاع و عرض آن محاسبه و برمیگرداند.
calcArea() { return this.height * this.width; } }
سپس نمونه از کلاس Rectangle به نام square با ابعاد 10 در 10 ایجاد میکنیم. در نهایت از «console.log(square.area)» برای چاپ مساحت محاسبهشده مربع که 100 است استفاده میکنیم.
const square = new Rectangle(10, 10); console.log(square.area); // Output: 100
حال، بیایید این را با کد معادل با استفاده از سینتکس سنتی مبتنی بر prototype در جاوا اسکریپت مقایسه کنیم:
function Rectangle(height, width) { this.height = height; this.width = width; } Rectangle.prototype.calcArea = function calcArea() { return this.height * this.width; };
در این سینتکس سنتی، ما یک تابع سازنده Rectangle ایجاد میکنیم و متد calcArea به نمونه اولیه Rectangle اضافه میشود. سینتکس کلاس اساساً روشی مختصر و قابلخواندن برای دستیابی به همان نتیجهای است که روش سنتی مبتنی بر نمونه اولیه است.
به طور خلاصه، کلاسهای جاوا اسکریپت نحو تمیزتر برای کار با نمونههای اولیه ارائه میکنند که آن را برای توسعهدهندگان آشنا با مفاهیم OOP قابلدرکتر میسازد. با این حال، درک این نکته ضروری است که کلاسهای جاوا اسکریپت همچنان از زنجیره اولیه برای ارث بردن استفاده میکنند.
📷
در جاوا اسکریپت، میتوان تابع سازنده را با اضافه کردن متدهای جدید به آن با استفاده از نمونه اولیه، تقویت کرد. بیایید یک مثال را برای توضیح این موضوع مرور کنیم:
// Define a constructor function function Person() { this.name = 'John'; this.age = 23; } // Create two objects using the constructor function const person1 = new Person(); const person2 = new Person(); // Add a new method to the constructor function using prototype Person.prototype.greet = function() { console.log('Hello ' + this.name); }; // Call the newly added method on both objects person1.greet(); // Output: Hello John person2.greet(); // Output: Hello John
توضیح کد فوق به صورت زیر است:
خط اول از مثال بالا تابع سازنده به نام Person را تعریف میکند که به عنوان طرحی برای ایجاد اشیایی با ویژگیهایی مانند name و age عمل میکند. در سازنده Person، ویژگیهای name و age با مقادیر خاصی برای هر نمونه شی مقداردهی اولیه میشوند.
function Person() { this.name = 'John'; this.age = 23; }
خطوط بعدی استفاده از تابع سازنده Person دو شی (person1 و person) ایجاد میکند.
const person1 = new Person(); const person2 = new Person();
در ادامه متدی جدید به نام greet را به نمونه اولیه تابع سازنده Person اضافه میکنیم. این متد نوعی پیام تبریک شامل نام شخص را چاپ میکند.
Person.prototype.greet = function() {
بعد متد gree رشته Hello را با نام Person الحاق و پیام به دست آمده را در کنسول ثبت میکند.
console.log('Hello ' + this.name);
در نهایت این خطوط متد greet را در هر دو شیء فراخوانی میکنند و در نتیجه نوعی تبریک شخصی برای هر شخص نمایش داده میشود.
person1.greet(); // Output: Hello John person2.greet(); // Output: Hello John
افزودن متدها به یک تابع سازنده با استفاده از prototype در جاوا اسکریپت، به تمام اشیاء ایجاد شده از آن سازنده اجازه میدهد تا از متد مشابه استفاده کنند. این کارایی کد و قابلیت استفاده مجدد را افزایش میدهد.
prototype در جاوا اسکریپت مکانیزم قدرتمندی هستند که به ارث بری در جاوا اسکریپت استفاده از آنها امکانپذیر میشود. هر تابع و شی دارای نوعی نمونه اولیه است که به عنوان الگویی برای ویژگی و متدها عمل میکند. اشیاء ایجاد شده از تابع سازنده، ویژگیها و متدها را از نمونه اولیه آن به ارث میبرند که سازماندهی کد کارآمد را تسهیل میکند و قابلیت استفاده مجدد را ارتقا میدهد. زنجیره نمونه اولیه هم نوعی رویکرد ساختاریافته برای به اشتراک گذاشتن توابع در بین اشیا را امکانپذیر میکند. درک نمونههای اولیه برای تسلط بر قابلیتهای شی گرای جاوا اسکریپت از مفاهیم اساسی است.
با مطالعه مقالات مختلف و دیدن ویدیوهای آموزشی، ممکن است به بخشهای مختلف جاوا اسکریپت آشنا شوید، اما بدون برنامه و رویه یادگیری مناسب، ممکن است احساس دلسردی کنید یا حتی نتوانید بهصورت کامل این زبان برنامهنویسی را فرا بگیرید. اگر نگران این موضوع هستید، تیم سبزلرن برای شما دوره آموزشی کامل از مبتدی تا حرفهای جاوا اسکریپت را فراهم کرده است که به صورت رایگان در دسترس قرار دارد.
این دوره علاوه بر ارائه رایگان، دارای پشتیبانی آنلاین نیز است. این فرصت بینظیری است که میتوانید از آن بهرهمند شوید. پس به دوره نام برده ملحق شده و یادگیری حرفهای جاوا اسکریپت را شروع کنید.