33- آموزش جاوااسکریپت | Constructor و کلیدواژه this
در این آموزش با دو مفهوم مهم در برنامهنویسی شیگرا در جاوااسکریپت آشنا میشویم: constructor و کلیدواژه this. همچنین تفاوت بین Object Literal و Constructor Function را بررسی میکنیم و یاد میگیریم چگونه با استفاده از new چندین نمونه از یک شیء بسازیم.
در این بخش وارد یکی از مهمترین مباحث برنامهنویسی شیگرا در جاوااسکریپت میشویم: تابع سازنده (constructor) و کلیدواژه this.
بعدتر با classها و ساختار مدرنتر ES6 هم کار خواهیم کرد، اما پیش از آن بهتر است درک کنیم این مفاهیم در سطح پایینتر و در ساختار ES5 چگونه کار میکنند. کلاسهای ES6 در واقع روشی سادهتر و خواناتر برای نوشتن کد شیگرا هستند، اما درک سازوکار اصلی آنها اهمیت زیادی دارد.
Object Literal چیست؟
تا اینجا دیدهایم که میتوان یک شیء را با استفاده از Object Literal ساخت. این روش برای زمانی مناسب است که فقط با یک شیء سروکار داریم.
const matin = {
name: 'Matin',
age: 36
};
console.log(matin);
console.log(matin.name);
console.log(matin.age);
در این ساختار، شیء از مجموعهای از جفتهای کلید و مقدار تشکیل میشود. این روش ساده و کاربردی است، اما اگر بخواهیم چندین شیء مشابه ایجاد کنیم، بهتر است از constructor استفاده کنیم.
چرا به Constructor نیاز داریم؟
اگر قرار باشد چندین نمونه از یک نوع شیء بسازیم، استفاده از Object Literal مناسب نیست، چون باید هر بار ساختار شیء را از ابتدا تکرار کنیم. در این شرایط، تابع سازنده راهحل بهتری است.
ساخت یک Constructor Function
در جاوااسکریپت ES5، برای ساخت سازنده از یک تابع معمولی استفاده میکنیم. طبق قرارداد، نام این تابع با حرف بزرگ شروع میشود.
function Person() {
this.name = 'Matin';
}
در اینجا یک سازنده به نام Person ساختهایم که فقط یک ویژگی به نام name دارد.
ساخت نمونه با استفاده از new
برای ساخت یک شیء از روی سازنده، از کلیدواژه new استفاده میکنیم.
function Person() {
this.name = 'Matin';
}
const matin = new Person();
console.log(matin);
خروجی این کد یک شیء خواهد بود که ویژگی name آن برابر با 'Matin' است.
مشکل مقدار ثابت در Constructor
اگر چند شیء مختلف از این سازنده ایجاد کنیم، همه آنها مقدار یکسانی خواهند داشت، چون مقدار name بهصورت ثابت تعریف شده است.
function Person() {
this.name = 'Matin';
}
const matin = new Person();
const john = new Person();
console.log(matin);
console.log(john);
در این مثال، هر دو شیء مقدار name برابر با 'Matin' خواهند داشت. برای حل این مشکل باید از پارامتر استفاده کنیم.
ارسال مقدار به Constructor
با دریافت آرگومان در تابع سازنده، میتوان هنگام ساخت هر نمونه، مقادیر متفاوتی به آن داد.
function Person(name) {
this.name = name;
}
const matin = new Person('Matin');
const john = new Person('John');
console.log(matin.name);
console.log(john.name);
اکنون هر شیء مقدار name مخصوص به خودش را دارد.
کلیدواژه this چه کاری انجام میدهد؟
کلیدواژه this به نمونهای از شیء اشاره میکند که در حال ساخته شدن است. در واقع، داخل constructor، عبارت this.name = name یعنی ویژگی name را روی همان شیء جدید قرار بده.
بررسی مقدار this داخل Constructor
اگر this را داخل سازنده چاپ کنیم، مقدار آن همان نمونهای است که با new ساخته شده است.
function Person(name) {
this.name = name;
console.log(this);
}
const matin = new Person('Matin');
const john = new Person('John');
چون دو نمونه ساختهایم، مقدار this نیز دو بار در کنسول نمایش داده میشود و هر بار به نمونه جاری اشاره دارد.
مقدار this در محدوده سراسری
اگر this را خارج از هر تابع و در محدوده سراسری مرورگر استفاده کنیم، به شیء window اشاره خواهد کرد.
console.log(this);
در محیط مرورگر، خروجی این کد شیء window است.
حتی میتوان به متدهای window از طریق this دسترسی داشت:
this.alert('Hello');
این اتفاق به این دلیل رخ میدهد که در محدوده سراسری مرورگر، this همان window است.
افزودن ویژگیهای بیشتر به Constructor
میتوانیم ویژگیهای دیگری هم به سازنده اضافه کنیم. برای مثال، علاوه بر نام، سن را نیز ذخیره کنیم.
function Person(name, age) {
this.name = name;
this.age = age;
}
const matin = new Person('Matin', 36);
const john = new Person('John', 30);
console.log(john.age);
استفاده از تاریخ تولد بهجای سن
گاهی بهتر است بهجای ذخیره مستقیم age، تاریخ تولد را نگه داریم و سن را بر اساس آن محاسبه کنیم.
function Person(name, dob) {
this.name = name;
this.birthday = new Date(dob);
}
const matin = new Person('Matin', '10-23-1989');
console.log(matin);
در اینجا مقدار dob بهصورت رشته دریافت میشود، اما با استفاده از new Date(dob) آن را به یک شیء تاریخ تبدیل میکنیم.
تعریف متد داخل Constructor
علاوه بر ویژگیها، میتوانیم متد نیز داخل سازنده تعریف کنیم. متد در واقع تابعی است که به یک شیء تعلق دارد.
در مثال زیر، متدی برای محاسبه سن تعریف میکنیم:
function Person(name, dob) {
this.name = name;
this.birthday = new Date(dob);
this.calculateAge = function () {
const diff = Date.now() - this.birthday.getTime();
const ageDate = new Date(diff);
return Math.abs(ageDate.getUTCFullYear() - 1970);
};
}
const matin = new Person('Matin', '10-23-1989');
console.log(matin.calculateAge());
منطق محاسبه سن
در متد calculateAge این مراحل انجام میشود:
- با
Date.now()زمان فعلی دریافت میشود. - با
this.birthday.getTime()زمان تولد بهصورت timestamp گرفته میشود. - اختلاف این دو مقدار محاسبه میشود.
- اختلاف به یک شیء
Dateتبدیل میشود. - با
getUTCFullYear()سال استخراج میشود. - در نهایت با کم کردن
1970، سن به دست میآید.
برای اطمینان از مثبت بودن نتیجه نیز از Math.abs() استفاده شده است.
نکته درباره Math
شیء Math با بسیاری از اشیای دیگر جاوااسکریپت تفاوت دارد، چون برای استفاده از آن نیازی به new نداریم.
console.log(Math.abs(-10));
اما در مورد Date باید از سازنده استفاده کنیم:
const today = new Date();
جمعبندی
در این آموزش دیدیم که:
Object Literalبرای ساخت یک شیء ساده مناسب است.- وقتی به چند نمونه مشابه نیاز داریم، بهتر است از
Constructor Functionاستفاده کنیم. - با کلیدواژه
newمیتوان از روی سازنده، نمونههای جدید ساخت. - کلیدواژه
thisداخل سازنده به شیء در حال ایجاد اشاره میکند. - میتوان هم ویژگی و هم متد را داخل
constructorتعریف کرد. - با استفاده از
DateوMathمیتوان متدهای کاربردیتری برای اشیاء ساخت.
این مفاهیم پایهای هستند و در ادامه مسیر یادگیری برنامهنویسی شیگرا، درک آنها برای کار با prototype، inheritance و class بسیار مهم خواهد بود.