یک constructor پیشرفته تر

20 آبان 1398
02-OOP-JS

جاوا اسکریپت OOP: یک constructor پیشرفته تر

در قسمت قبل با یک مثال ساده روبرو شدیم که چنین شکلی داشت:

function Person(name, age) {
    this.name = name;
    this.age = age;
}

const Amir = new Person('Amir', 24);
const Erfan = new Person('Erfan', 26);
console.log(Amir.age);

این مثال بیش از حد ساده است، بیایید کمی پیشرفته تر کار کنیم اما قبل از انجام این کار بهتر است در مورد شیء Date خلاصه ای برایتان بگویم. شیء Date به یک زمان خاص اشاره می کند و برای ساختن آن باید از کلیدواژه ی new استفاده کنید. توجه داشته باشید که اگر آن را به شکل زیر صدا بزنید:

now = Date()

نتیجه فقط یک رشته خواهد بود و دیگر قابلیت های شیء Date را نخواهد داشت. اگر به Date هیچ پارامتری را پاس ندهید، زمان حال را در نظر خواهد گرفت. به مثال زیر توجه کنید:

var date1 = new Date('December 17, 1995 03:24:00');
// Sun Dec 17 1995 03:24:00 GMT...

var date2 = new Date('1995-12-17T03:24:00');
// Sun Dec 17 1995 03:24:00 GMT...

console.log(date1 === date2);

console.log(date1 - date2);

نتیجه ی console.log اول false و نتیجه ی console.log دوم عدد صفر است. همانطور که می بینید هر دو تاریخ بالا یکی هستند و فقط نحوه ی قالب بندی تاریخ فرق دارد. من این موارد را در دو مقاله ی زیر مفصلا توضیح داده ام:

حالا در این مثال می خواهم به جای سن کاربر، تاریخ تولد او را به صورت رشته (string) دریافت کرده و آن را به صورت تاریخ ذخیره کنم! اگر یادتان باشد برای ساختن تاریخ از شیء Date (از اشیاء هسته ی جاوا اسکریپت) کمک می گرفتیم. بنابراین می توان گفت:

function Person(name, dob) {
    this.name = name;
    this.age = new Date(dob);
}

const Amir = new Person('Amir', '8-20-1990');
console.log(Amir);

dob مخفف date of birth (تاریخ تولد) است و من آن را به عنوان یک پارامتر دریافت کرده و به constructor شیء Date داده ام. شیء Date از اشیاء هسته ی جاوا اسکریپت است و constructor آن قبلا توسط تیم توسعه ی جاوا اسکریپت، کدنویسی شده است. خروجی دستور بالا به شکل زیر است:

خروجی تولد در متد calculateAge
خروجی تولد در متد calculateAge

همانطور که می بینید تاریخ تولد به صورت کامل برای این شیء ساخته شده است. البته تاریخ تنها چیزی نیست که می توانیم به constructor اضافه کنیم. من می خواهم یک متد را نیز به این constructor اضافه کنم! متد ها در واقع توابعی هستند که درون یک شیء (کلاس ها و constructor ها) قرار دارند. متدی که من می خواهم اضافه کنم calculateAge نام دارد و سن کاربر را محاسبه خواهد کرد (در حال حاضر تاریخ تولد را داریم اما سن را نداریم):

function Person(name, dob) {
    this.name = name;
    this.birthday = new Date(dob);
    this.calculateAge = function (){

    }
}

همانطور که می بینید شروع تعریف یک متد دقیقا به شکل تعریف یک تابع anonymous است. توجه داشته باشید که من age را به birthday تغییر دادم تا نام بهتری داشته باشیم. روش های مختلفی برای محاسبه ی سن کاربر وجود دارد، من روش زیر را انتخاب کرده ام:

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);
    }
}

در کد بالا ثابت diff تفاوت بین زمان حال (date.now) و زمان تولد (birthday.getTime) را در خود نگه می دارد. ثابت ageDate نیز یک شیء Date (تاریخ) از این تفاوت می سازد چرا که در حال حاضر getTime را استفاده کرده ایم و مقدار diff بر اساس unix است (تعداد ثانیه ها از سال 1970). در نهایت با Math.abs مطمئن شده ایم که خروجی ما عددی مثبت است. متد getUTCFullYear نیز سال را بر اساس استاندارد UTC دریافت می کند.

برای تست این کد می توانیم از آن خروجی بگیریم:

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 Amir = new Person('Amir', '8-20-1990');
console.log(Amir.calculateAge());

خروجی عدد 29 خواهد بود که صحیح است.

Constructor های جاوا اسکریپت

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

به یکی از این Constructor ها نگاه کنید:

const name1 = "Jeff";
const name2 = new String('Jeff');

بله با استفاده از شیء String یک رشته را به صورت یک شیء ساخته ایم! اگر متغیر name1 را console.log کنیم با یک مقدار رشته ای ساده روبرو می شویم:

رشته ی Jeff
رشته ی Jeff

اما اگر متغیر name2 را Console.log کنیم با یک شیء مواجه می شویم که علاوه بر رشته ی ما دارای تک تک حروف رشته ی ما نیز می باشد:

شیء Jeff
شیء Jeff

این روش چندین و چند نوع مشکل ایجاد می کند و علاوه بر آن هیچ دلیل منطقی برای استفاده از آن وجود ندارد. یکی از مشکلات معمول این روش این است که در مقایسه ها و عبارات شرطی جواب اشتباه را می گیریم! به مثال زیر توجه کنید:

if (name1 === 'Jeff') {
    console.log('yes');
} else {
    console.log('no');
}

اگر کد بالا را اجرا کنیم پاسخ Yes خواهد بود چرا که name1 از نوع string می باشد اما اگر به جای name1 متغیر name2 را بگذاریم:

if (name2 === 'Jeff') {
    console.log('yes');
} else {
    console.log('no');
}

حالا پاسخ دریافتی ما No خواهد بود. چرا؟ به دلیل اینکه name2 یک شیء است اما ‘Jeff’ یک رشته است. شاید شما بگویید باید به جای استفاده از اپراتور === از اپراتور == استفاده کنیم. اگر این کار را بکنیم مشکل این مثال حل می شود اما بسیاری از اوقات نیاز است تا type یک متغیر را نیز چک کنیم و اگر رشته را به شکل شیء ساخته باشیم دیگر نمی توانیم از اپراتور === استفاده کنیم یا حداقل باید کد ها را دستکاری کنیم.

Constructor های دیگری نیز وجود دارند که همگی این مشکل را دارند:

/ Number
const num1 = 5;
const num2 = new Number(5);

// Boolean
const bool1 = true;
const bool2 = new Boolean(true);

// Object
const john1 = {name: "John"};
const john2 = new Object({name: "John"});
console.log(john2);

// Arrays
const arr1 = [1,2,3,4];
const arr2 = new Array(1,2,3,4);

// Regular Expressions
const re1 = /\w+/;
const re2 = new RegExp('\\w+');

البته از موارد بالا آرایه ها و اشیاء هیچ تفاوتی در دو روش ساخت ندارند. یعنی چه با کلیدواژه ی new و چه به صورت عادی آن ها را بنویسید فرقی ایجاد نمی شود اما بهتر است از روش اول استفاده کنید و با کلیدواژه ی new استفاده نکنید چرا که یکی دیگر از معایب آن پایین آمدن سرعت برنامه است.

در قسمت بعد در رابطه با Prototype معروف بحث خواهیم کرد.

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

دیدگاه‌های شما

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