شی‌ گرایی در جاوا اسکریپت — به زبان ساده

۸۳۳ بازدید
آخرین به‌روزرسانی: ۰۸ شهریور ۱۴۰۲
زمان مطالعه: ۱۱ دقیقه
شی‌ گرایی در جاوا اسکریپت — به زبان ساده

در بخش قبلی این سلسله مطالب آموزش عملی جاوا اسکریپت به بررسی مفهوم کلاس و شیئ پرداختیم. اینک که با مبانی قضیه آشنا شدیم می‌توانیم روی شی‌ گرایی در جاوا اسکریپت متمرکز شویم و سپس شبیه‌سازی کلاس‌های شیئ به وسیله جاوا اسکریپت از سوی تابع‌های سازنده و شیوه ایجاد نمونه‌های از شیئ را مورد بررسی قرار دهیم.

پیش‌نیازها

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

مبانی برنامه‌نویسی شیئ‌گرا

در آغاز یک دید ساده و نمای سطح بالا از مفهوم برنامه‌نویسی شیئ‌گرا ارائه می‌کنیم. منظور از ساده این است که برنامه‌نویسی شیئ‌گرا می‌تواند به سرعت پیچیده شود و بررسی این وضعیت پیش از آن که کمکی به ما بکند موجب سردرگمی بیشتر ما خواهد شد. ایده اساسی برنامه‌نویسی شیئ‌گرا این است که از اشیا و مدل‌های دنیای واقعی که قرار است در برنامه ما ایفای نقش کنند، استفاده کنیم و/یا روشی ساده برای دسترسی کارکردهایی بیابیم که به جز این طریق بهره‌برداری از آن‌ها بسیار دشوار می‌بود.

اشیا می‌توانند شامل داده‌ها و کد مرتبط باشند که اطلاعاتی در مورد چیزی که قصد داریم مدلسازی کنیم ارائه می‌دهند و کارکرد یا رفتاری را شامل می‌شوند که می‌خواهیم در برنامه خود بگنجانیم. داده‌های شیئ (و در اغلب موارد تابع‌ها نیز) می‌توانند درون یک بسته شیئ ذخیره (کپسوله‌سازی) شوند و به این ترتیب نام خاصی به دست می‌آوریم که می‌توانیم مورد ارجاع قرار دهیم که در برخی موارد namespace نام دارد و موجب سهولت سازماندهی و دسترسی می‌شود. شیئ به طور معمول به عنوان data store استفاده می‌شود که به راحتی روی شبکه ارسال می‌شود.

تعریف قالب یک شیئ

در ادامه برنامه ساده‌ای را بررسی می‌کنیم که به نمایش اطلاعاتی در مورد دانش‌آموزان و معلمان در یک مدرسه می‌پردازد. در این بخش به بررسی نظریه برنامه‌نویسی شیئ‌گرا در یک چارچوب کلی و نه در زمینه‌ای خاص می‌پردازیم.

برای آغاز می‌توانیم از شیئ Person که در بخش قبلی این راهنما معرفی کردیم، استفاده کنیم. در این شیئ به تعریف داده‌ها و کارکرد ژنریک یک «شخص» پرداختیم. چیزهای زیادی وجود دارند که می‌توان در مورد یک فرد به آن‌ها اشاره کرد که برای مثال شامل نشانی، قد، اندازه کفش، پروفایل DNA، شماره گذرنامه، خصیصه‌های شخصیتی مهم و غیره می‌شود؛ اما در مثال خود صرفاً به نام، سن، جنسیت و علایق هر فرد اکتفا می‌کنیم و همچنین می‌خواهم بتوانیم یک توصیف (bio) کوتاه در مورد آن‌ها بر مبنای داده‌هایشان بنویسیم. این کار «تجرید» (abstraction) نام داد، یعنی یک مدل ساده از یک چیز پیچیده‌تر می‌سازیم که جنبه‌های مهم‌تر آن را به ترتیبی نمایش می‌دهد که کار با آن به منظور پیگیری مقاصد برنامه آسان‌تر خواهد بود.

ایجاد شیئ‌های واقعی

ما در کلاس خود می‌توانیم نمونه شیئ را بسازیم. منظور از نمونه یک شیئ در واقع شیئ‌هایی هستند که شامل داده‌ها و کارکرد تعریف شده در کلاس هستند. ما اینک می‌توانیم از کلاس Person خود شیئ‌های واقعی Person ایجاد کنیم:

زمانی که یک نمونه (instance) از شیئ از روی کلاس ساخته می‌شود، تابع سازنده کلاس اجرا می‌شود تا آن را ایجاد کند. فرایند ایجاد یک نمونه از شیئ از یک کلاس به نام «نمونه‌سازی» (instantiation) نام دارد و در این حالت گفته می‌شود که نمونه شیئ از کلاس مربوطه «نمونه‌سازی» (instantiated) شده است.

کلاس تخصص‌ها

در این مثال ما به افراد کلی علاقه‌مند نیستیم و می‌خواهیم معلم و دانش‌آموز داشته باشیم که هر دو نوع خاصی از فرد هستند. در برنامه‌نویسی شیئ‌گرا می‌توانیم کلاس‌های جدید را بر مبنای کلاس‌هایشان ایجاد کنیم که این موارد «کلاس‌های فرزند» (child classes) نامیده می‌شوند و می‌توانند داده و ویژگی‌های کد را از «کلاس‌های والد» (parent class) به ارث ببرند. بدین ترتیب می‌توانید کارکردهای مشترک میان همه انواع شیئ‌ها را به جای بازنویسی مورد استفاده مجدد قرار دهید. زمانی که یک کارکرد بین کلاس‌های مختلف، متفاوت باشد می‌توانیم ویژگی‌های تخصصی را مستقیماً روی آن‌ها بسته به نیاز تعریف کنیم.

این ویژگی کاملاً مفید است چون دانش‌آموزان و معلمان ویژگی‌های مشترک زیادی مانند نام، جنسیت، سن و غیره دارند و از این رو می‌توانیم این ویژگی‌های را به سادگی تنها یک بار تعریف کنیم. همچنین می‌توانیم برخی ویژگی‌ها را به صورت جداگانه در کلاس‌های مختلف تعریف کنیم چون هر تعریفی از آن ویژگی در فضای نام متفاوتی خواهد بود. برای نمونه معرفی یک دانش‌آموز می‌تواند به صورت «سلام، من میثم هستم» باشد در حالی که معلم ممکن است از توصیف رسمی‌تری مانند «سلام، نام من میثم لطفی است و ریاضیات تدریس می‌کنم.» باشد.

نکته: اصطلاحی که برای توصیف امکان پیاده‌سازی‌های چندگانه برای کارکرد یکسان استفاده می‌شود «چندریختی» (polymorphism) نام دارد.

اینک می‌توانیم نمونه‌هایی از شیئ را از کلاس‌های فرزند به صورت زیر ایجاد کنیم:

در ادامه این مقاله به بررسی چگونگی استفاده عملی از نظریه برنامه‌نویسی شیئ‌گرا در جاوا اسکریپت خواهیم پرداخت.

سازنده‌ها و نمونه‌های شیئ

جاوا اسکریپت از برخی تابع‌های خاص به نام «تابع‌های سازنده» (constructor functions) برای تعریف اشیا و ویژگی‌های آن‌ها استفاده می‌کند. این‌ها موارد مفیدی هستند زیرا می‌توانید در اغلب موارد در موقعیت‌هایی که نمی‌دانید چند چیز ایجاد خواهند شد از آن‌ها استفاده کنید. سازنده‌ها ابزاری برای ایجاد اشیای بسیار بسته به نیاز و به روشی کارآمد ارائه می‌کنند و بدین ترتیب داده‌ها و تابع‌ها را در صورت لزوم به آن‌ها ارتباط می‌دهند.

در ادامه به بررسی روش ایجاد کلاس از طریق سازنده و ایجاد نمونه‌های شیئ‌ از آن‌ها در جاوا اسکریپت می‌پردازیم. قبل از هر چیز باید یک فایل به نام oojs.html در سیستم خود ایجاد کرده و کد زیر را در آن قرار دهید.

1<!DOCTYPE html>
2<html>
3  <head>
4    <meta charset="utf-8">
5    <title>Object-oriented JavaScript example</title>
6  </head>
7
8  <body>
9    <p>This example requires you to enter commands in your browser's JavaScript console (see <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools</a> for more information).</p>
10
11  </body>
12
13    <script>
14    </script>
15</html>

یک مثال ساده

کار خود را با بررسی روش تعریف یک فرد با استفاده از تابع نرمال آغاز می‌کنیم. این تابع درون عنصر script قرار دارد:

1function createNewPerson(name) {
2  var obj = {};
3  obj.name = name;
4  obj.greeting = function() {
5    alert('Hi! I\'m ' + obj.name + '.');
6  };
7  return obj;
8}

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

1var salva = createNewPerson('Salva');
2salva.name;
3salva.greeting();

این کد به نحو احسن کار می‌کند؛ اما کمی طولانی است. سؤال این است که اگر ما می‌دانیم چگونه می‌توانیم یک شیئ را بسازیم، چرا نباید یک شیئ خالی جدید را صریحاً تعریف کرده و آن را بازگشت دهیم؟ خوشبختانه جاوا اسکریپت یک میانبر کارآمد در اختیار ما قرار داده است که به شکل تابع‌های سازنده است. در ادامه یک تابع سازنده می‌نویسیم. بدین منظور کافی است تابع قبلی را با مورد زیر جایگزین کنید:

1function Person(name) {
2  this.name = name;
3  this.greeting = function() {
4    alert('Hi! I\'m ' + this.name + '.');
5  };
6}

تابع سازنده در واقع نسخه جاوا اسکریپت از یک کلاس محسوب می‌شود. متوجه خواهید شد که این تابع همه ویژگی‌هایی که از یک تابع انتظار داریم را دارد؛ اما هیچ چیزی را بازگشت نمی‌دهد و یا یک شیئ را به صورت مستقیم ایجاد نمی‌کند. در واقع تابع سازنده صرفاً به تعریف کردن مشخصه‌ها و متدها می‌پردازد. همان طور که می‌بینید کلیدواژه this در این جا نیز به خوبی ‌استفاده شده است. این کلیدواژه در واقع بیان می‌کند که ه رزمان یکی از این نمونه‌های شیئ ایجاد شد، مشخصه name برابر با مقدار نام ارسالی به فراخوانی سازنده خواهد بود و متد ()greeting از مقدار name که به سازنده نیز ارسال شده استفاده خواهد کرد.

نکته: یک نام تابع سازنده به طور معمول با حرف بزرگ شروع می‌شود. این قرارداد برای این وضع شده که تابع‌های سازنده در کد به راحتی شناسایی شوند. اکنون سؤال این است که چگونه می‌توانیم یک سازنده را برای ایجاد برخی اشیا فراخوانی کنیم؟ خط‌های زیر را به کد قبلی خود اضافه کنید:

1var person1 = new Person('Bob');
2var person2 = new Person('Sarah');

کد خود را ذخیره کرده و آن را در مرورگر بارگذاری مجدد کنید و خط‌های زیر را در کنسول جاوا اسکریپت مرورگر وارد نمایید:

1person1.name
2person1.greeting()
3person2.name
4person2.greeting()

اینک متوجه خواهید شد که دو شیئ جدید روی صفحه داریم که هر کدام از آن‌ها تحت فضای نام متفاوتی ذخیره‌ شده‌اند. زمانی که به مشخصه‌ها و متدهای آن‌ها مراجعه کنیم، باید فراخوانی را با نام‌های person1 یا person2 انجام دهیم. کارکرد موجود درون آن‌ها به طور کامل از دسترس ما خارج است و از این رو با کارکردهای دیگر تصادم پیدا نمی‌کند. با این وجود، مشخصه name آن‌ها یکسان است و متد ()greeting نیز وجود دارد.

دقت کنید که هر دو این شیئ‌ها مقدار name خاص خود را دارند که در زمان ایجاد به آن‌ها انتساب یافته است. این یکی از دلایلی است که چرا استفاده از this مهم است، چون بدین ترتیب آن‌ها هر کدام از مقادیر خود استفاده می‌کنند و با مقادیر شیئ‌هایی که نام یکسان دارند اشتباه گرفته نمی‌شوند. در ادامه یک بار دیگر نگاهی به فراخوانی تابع‌های سازنده می‌اندازیم:

1var person1 = new Person('Bob');
2var person2 = new Person('Sarah');

در هر مورد کلیدواژه this برای این موضوع استفاده شده است که به مرورگر اعلام کند می‌خواهیم یک نمونه جدید از شیئ ایجاد کنیم که پس از آن نام تابع به همراه پارامترهای الزامی درون پرانتز ارائه می‌شود و نتیجه در یک متغیر ذخیره می‌شود که فرایندی کاملاً مشابه شیوه استاندارد فراخوانی تابع است. هر نمونه بر اساس این تعریف ایجاد می‌شود:

1function Person(name) {
2  this.name = name;
3  this.greeting = function() {
4    alert('Hi! I\'m ' + this.name + '.');
5  };
6}

پس از این که اشیای جدید ایجاد شدند، متغیرهای person1 و person2 شامل اشیای زیر خواهند بود:

1{
2  name: 'Bob',
3  greeting: function() {
4    alert('Hi! I\'m ' + this.name + '.');
5  }
6}
7
8{
9  name: 'Sarah',
10  greeting: function() {
11    alert('Hi! I\'m ' + this.name + '.');
12  }
13}

دقت کنید که وقتی تابع سازنده ما فراخوانی می‌شود در واقع هر بار ()greeting را تعریف می‌کنیم که فرایند مناسبی محسوب نمی‌شود. برای اجتناب از این وضعیت می‌توانیم تابع‌ها را روی پروتوتایپ تعریف کنیم که این وضعیت را در ادامه بیشتر بررسی خواهیم کرد.

ایجاد سازنده نهایی

مثالی که در بخش قبلی بررسی کردیم، تنها نمونه ساده‌ای بود که صرفاً به منظور آغاز بحث استفاده شد. اینک تابع سازنده ()Person نهایی خود را به صورت عملی می‌سازیم.

ابتدا کدهایی که تا اینجا نوشته‌ایم را پاک کنید و به جای آن سازنده زیر را اضافه کنید. این کد در واقع دقیقاً همان مثال ساده مورد بحث است که کمی پیچیده‌تر شده است:

1function Person(first, last, age, gender, interests) {
2  this.name = {
3    'first': first,
4    'last' : last
5  };
6  this.age = age;
7  this.gender = gender;
8  this.interests = interests;
9  this.bio = function() {
10    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
11  };
12  this.greeting = function() {
13    alert('Hi! I\'m ' + this.name.first + '.');
14  };
15}

سپس خط زیر را اضافه کنید تا یک نمونه از شیئ ساخته شود:

1var person1 = new Person('Bob'، 'Smith'، 32، 'male'، ['music'، 'skiing']);

اینک می‌بینید که می‌توانید به مشخصه‌ها و متدها، همانند قبل دسترسی داشته باشید. موارد زیر را در کنسول جاوا اسکریپت مرورگر وارد کنید:

1person1['age']
2person1.interests[1]
3person1.bio()
4// etc.

تمرین‌های بیشتر

برای این که مثال خود را کمی بسط دهید در ادامه خطوط ایجاد شیئ بیشتری را به کد خود اضافه کنید و اعضای نمونه‌‌های شیئ حاصل را دریافت کرده و یا تعیین کنید.

به علاوه چند مشکل در مورد متد ()bio وجود دارند چون خروجی همواره شامل ضمیر «He» است، حتی اگر فرد مذکور زن باشد نیز همچنان از این ضمیر استفاده می‌شود. بخش bio نیز تنها شامل دو علاقه‌مندی است حتی اگر موارد بیشتری در آرایه interests وارد شده باشند، همیشه تنها دو مورد نمایش می‌یابد. آیا شما می‌توانید این موارد را در تعریف کلاس (سازنده) حل کنید؟ شما می‌توانید هر گونه کدی را درون یک سازنده قرار دهید. در واقع احتمالاً به چند گزاره شرطی و یک حلقه نیاز خواهید داشت. در مورد این مسئله‌ها فکر کنید و ببینید جمله‌ها چگونه به طرز متفاوتی بسته به جنسیت و بسته به تعداد علاقه‌مندی‌های به تعداد 1، 2 یا بیشتر می‌توانند ترکیب شوند.

اگر نتوانستید این مسائل را حل کنید، می‌توانید از کد اصلاح شده زیر استفاده کنید:

1<!DOCTYPE html>
2<html>
3  <head>
4    <meta charset="utf-8">
5    <title>Object-oriented JavaScript class further exercises</title>
6  </head>
7
8  <body>
9    <p>This example requires you to enter commands in your browser's JavaScript console (see <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools</a> for more information).</p>
10
11  </body>
12
13    <script>
14      function Person(first, last, age, gender, interests) {
15        this.name = {
16          'first': first,
17          'last' : last
18        };
19        this.age = age;
20        this.gender = gender;
21        this.interests = interests;
22        this.bio = function() {
23          // First define a string, and make it equal to the part of
24          // the bio that we know will always be the same.
25          var string = this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. ';
26          // define a variable that will contain the pronoun part of
27          // the second sentence
28          var pronoun;
29          // check what the value of gender is, and set pronoun
30          // to an appropriate value in each case
31          if(this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
32            pronoun = 'He likes ';
33          } else if(this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
34            pronoun = 'She likes ';
35          } else {
36            pronoun = 'They like ';
37          }
38          // add the pronoun string on to the end of the main string
39          string += pronoun;
40          // use another conditional to structure the last part of the
41          // second sentence depending on whether the number of interests
42          // is 1, 2, or 3
43          if(this.interests.length === 1) {
44            string += this.interests[0] + '.';
45          } else if(this.interests.length === 2) {
46            string += this.interests[0] + ' and ' + this.interests[1] + '.';
47          } else {
48            // if there are more than 2 interests, we loop through them
49            // all, adding each one to the main string followed by a comma,
50            // except for the last one, which needs an and & a full stop
51            for(var i = 0; i < this.interests.length; i++) {
52              if(i === this.interests.length - 1) {
53                string += 'and ' + this.interests[i] + '.';
54              } else {
55                string += this.interests[i] + ', ';
56              }
57            }
58          }
59          // finally, with the string built, we alert() it
60          alert(string);
61        };
62        this.greeting = function() {
63          alert('Hi! I\'m ' + this.name.first + '.');
64        };
65      };
66      var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']);
67    </script>
68</html>

روش‌های دیگر برای ایجاد نمونه‌های شیئ

تا به اینجا دو روش متفاوت برای ایجاد یک نمونه از شیئ دیدیم که یکی اعلان یک «شیئ لفظی» (object literal) و دیگری استفاده از یک تابع سازنده است.

این دو روش‌های مناسبی هستند؛ اما روش‌های دیگری نیز برای نمونه‌سازی اشیا وجود دارند. در ادامه این روش‌ها را توضیح می‌دهیم تا وقتی در مسیر توسعه وب با آن‌ها مواجه شدید بتوانید آن‌ها را بشناسید.

سازنده ()Obejct

اولین روش استفاده از سازنده ()Obejct است که با آن می‌توان یک شیئ جدید ساخت. حتی اشیای ژنریک نیز یک سازنده دارند که یک شیئ خالی ایجاد می‌کند. کد زیر را در کنسول جاوا اسکریپت مرورگر وارد کنید:

1var person1 = new Object();

این دستور یک شیئ خالی در متغیر person1 ذخیره می‌کند. در ادامه می‌توانید مشخصه‌ها و متدها را با استفاده از یک نقطه یا نمادگذاری براکت (بسته به میل خودتان) به این شیئ اضافه کنید. برای مثال دستورهای زیر را در کنسول وارد کنید:

1person1.name = 'Chris';
2person1['age'] = 38;
3person1.greeting = function() {
4  alert('Hi! I\'m ' + this.name + '.');
5};

همچنین می‌توانید یک شیئ لفظی را به عنوان یک پارامتر به یک سازنده ()Object ارسال کنید تا آن را از قبل با مشخصه‌ها /متدها پر کنید. کد زیر را در کنسول وارد کنید:

1var person1 = new Object({
2  name: 'Chris',
3  age: 38,
4  greeting: function() {
5    alert('Hi! I\'m ' + this.name + '.');
6  }
7});

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

با این وجود، برخی افراد ترجیح می‌دهند که نمونه‌های شیئ را بدون ایجاد مقدماتی سازنده‌ها بسازند. این وضعیت به طور خاص در مواردی که تنها چند نمونه معدود از یک شیئ قرار است ساخته شود بیشتر مشاهده می‌شود. جاوا اسکریپت یک متد درونی به نام ()create دارد که امکان انجام این کار را فراهم می‌سازد. با استفاده از این متد می‌توانید یک شیئ جدید را بر مبنای شیئ موجود بسازید. زمانی که تمرین بخش قبلی را در مرورگر خود بارگذاری کردید، کد زیر را در کنسول مرورگر وارد کنید:

1var person2 = Object.create(person1);

اینک دستورهای زیر را وارد کنید:

1person2.name
2person2.greeting()

چنان که می‌بینید person2 بر مبنای person1 ساخته شده است و همان مشخصه‌ها و متدها را دارد. یک محدودیت ()create این است که IE8 از آن پشتیبانی نمی‌کند. بنابراین دیدیم که سازنده‌ها در صورتی که بخواهیم کد ما در مرورگرهای قدیمی نیز پشتیبانی شود، کارایی بیشتری خواهند داشت. در بخش‌های بعدی در مورد تأثیرات ()create بیشتر صحبت خواهیم کرد.

جمع‌بندی

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

اگر این مطالب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

^^

==

بر اساس رای ۳ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
developer.mozilla
نظر شما چیست؟

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