دیتا تایپها یکی از مباحث پایهای و مهم جاوااسکریپت هستن که در مصاحبههای استخدامی معمولا یک سوال از این مبحث مطرح میشه. تو این پست دربارهی دیتا تایپها و از اون مهمتر تفاوت اونها باهم، بحث میکنیم.
در جاوااسکریپت یا هر زبان برنامه نویسی دیگهای هر چیزی رو که بتونیم تو متغیر ذخیره کنیم، دیتا نامیده میشه. البته نوع دیتا با توجه به ماهیتشون، با هم تفاوت دارن.
const name = "Monica" const yearOfborn = 1964; let isAlive = true;
با توجه به کد بالا، متغیر name از نوع strring ، متغیر yearOfBorn از نوع number و متغیر isAlive از نوع boolean هستن.
در جاوااسکریپت به صورت کلی 10 نوع دیتا تایپ داریم.
این دیتا تایپها با توجه به ویژگیها و رفتارشون به دو دسته تقسیم میشن:
برای اینکه با رفتار این دسته از دیتا تایپها آشنا بشیم، بهتره با یک مثال شروع کنیم.
let x = 5; let y = x;
تو کد بالا ابتدا یک متغیر به نام x تعریف کردیم و مقدارش رو برابر با عدد 5 قرار دادیم. بعد یه متغیر دیگه به نام y تعریف کردیم و مقدارش رو برابر با مقدار متغیر x قرار دادیم.
الان اگه مقدار متغیر x رو تغیر بدیم، به نظرتون مقدار متغیر y هم تغیر میکنه یا نه؟
x = 10; console.log(y); // return 5
با تغیر مقدار متغیر x به عدد 10، مقدار متغیر y هیچ تغیری نمیکنه و همون مقدار قبلی که عدد 5 بود، باقی میمونه.
با نتایج بالا، مطمئنا این سوال براتون پیش میاد که چرا چنین اتفاقی افتاد؟
هنگامی که موتور جاوااسکریپت شروع به تفسیر کدمون میکنه، هر وقت به یه متغیر میرسه، مقدار اون متغیر رو چک میکنه؛ اگه مقدار متغیر، یکی از دیتا تایپهای primitive باشه، اون متغیر رو تو حافظه stack به عنوان یه متغیر مستقل ذخیره میکنه.
بعد اینکه متغیر x که دیتایی از نوع primitive داره، تو حافظه stack ذخیره شد، نوبت به متغیر y میرسه.
وقتی که موتور جاوااسکریپت به متغیر y رسید، مثل روال قبل، میره سراغ مقدار متغیر y. اینجا مقدار متغیر y به صورت مستقیم نوشته نشده. ولی جلوش یه حرف x است. چون x داخل " " یا ' ' یا ` ` نیست، پس اون رو به عنوان مقدار string نمیخونه و پیشبینی میکنه که این حرف به عنوان متغیر تو حافظه stack ذخیره شده. بنابراین حافظه stack رو بررسی میکنه تا ببینه آیا متغیری به اسم x وجود داره یا نه. اگه وجود داشته باشه، مقدار اون متغیر رو برمیداره و به عنوان مقدار متغیر y قرار میده. بعد از اینکه تکلیف مقدار متغیر y مشخص شد، موتور جاوااسکریپت اون رو با توجه به اینکه نوع مقدارش از نوع number و از دستهی primitiveها است، داخل حافظه stack به عنوان متغیر مستقل ذخیره میکنه.
اگه متغیری به اسم x رو قبلا تعریف نکرده بودیم و تو حافظه stack ذخیره نشده بود و موتور جاوااسکریپت مقداری برای متغیر y پیدا نمیکرد، به این نتیجه میرسید که مقداری برای متغیر y تعین نشده و undefined رو به عنوان مقدار اون در نظر میگرفت. همون طور که تو شکل بالا گفتیم، undefined هم یک دیتای primitive حساب میشه.
پس با وجود اینکه در ابتدا مقداری برای متغیر y تعین نشده بود، چون در نهایت مقدار undefined به اون اختصاص داده شد و undefined هم یک دیتای primitive محسوب میشه، در نهایت متغیر y هم به عنوان یک متغیر مستقل در حافظه stack ذخیره میشد.
بنابراین الان دو متغیر جدا و مستقل از هم به نامهای x و y داریم که هیچ ارتباطی به هم ندارن و اگه مقدار متغیر x رو تغیر بدیم، مقدار متغیر y تغیری نمیکنه.
حالا بهتره کمی دربارهی stack memory بدونیم.
حافظه stack نوعی از حافظه است که به سرعت قابل دسترسه. البته همون قدر که سریعه، محدود هم است. پس نمیتونه دیتای زیادی رو تو خودش ذخیره کنه. اگه بیشتر از ظرفیتش به اون دیتا وارد بشه، اصطلاحا گفته میشه: حافظه سرریز شد (stack over flow). به همین دلیل، این نوع حافظه مناسب دیتا تایپهای primitive است. چون برخلاف آرایهها، آبجکتها و فانکشنها، primitiveها آنچنان حجم زیادی ندارن.
دیتا تو حافظه stack به صورت منظم و بالای همدیگه قرار میگیرن.
برای شناخت این نوع از دیتا تایپها با مثال مشابهی که برای دیتا تایپهای primitives استفاده کردیم، شروع میکنیم.
let person = { name: "Steven", yerOfBorn: 1946 }; let person2 = person; person.name = "Christopher" console.log(person2.name); // return Christopher
اول یه آبجکت درست کردیم به اسم person که دو تا پراپرتی داره. بعد یه متغیر دیگه به اسم person2 ساختیم و مقدارش رو برابر با person قرار دادیم. بعد مقدار پراپرتی name آبجکت person رو تغیر دادیم.
در آخر وقتی مقدار پراپرتی name آبجکت person2 رو چک کردیم، متوجه شدیم مقدار پراپرتی name این آبجکت هم تغیر کرده. یعنی رفتار refrences کاملا برعکس رفتار primitives است.
ولی سوالی که حتما باز هم به ذهنتون میاد اینکه، چرا؟ چرا باید همچین رفتاری داشته باشن؟
همون طور که قبلا هم گفته شد، موقع تفسیر کدهای جاوااسکریپت، هر وقت موتور جاوااسکریپت به یک متغیر میرسه، مقدار اون متغیر چک میشه که آیا از نوع primitive است یا reference. در مثال قبل حالتی که نوع دیتا، primitive باشه رو بررسی کردیم.
وقتی دیتای ذخیره شده در متغیر از نوع reference باشه، موتور جاوااسکریپت ابتدا خود متغیر رو در حافظه stack ذخیره میکنه ولی مقدارش رو ذخیره نمیکنه. چون گفتیم حافظه stack محدوده و به دلیل اینکه دیتاهای reference حافظهی زیادی رو اشغال میکنن، باید اونها رو در یک حافظه دیگه ذخیره کنه و اون حافظه، heap نام داره. بنابراین به جای اینکه مقدار اون متغیر رو تو stack ذخیره کنه، یک آدرس رو به عنوان مقدار به اون میده که حافظه کمتری رو اشغال میکنه (برای درک بهتر موضوع، فرض کنیم اون آدرس یه آیدی عددی است). از این به بعد متغیری که در حافظه stack ذخیره شده به عنوان pointer شناخته میشه. چون به جای اینکه مقدار متغیر رو تو خودش ذخیره کنه، یه آدرسی رو ذخیره کرده که به جای اصلی مقدار متغیر در حافظه heap اشاره میکنه.
الان متغیر person یه pointer تو حافظه stack داره که اون pointer یه آدرس رو به عنوان مقدار داره و اون آدرس به جایی در حافظه heap اشاره میکنه که مقدار اصلی متغیر person اونجا ذخیره شده.
وقتی نوبت به متغیر person2 میرسه، باز هم موتور جاوااسکریپت متوجه میشه مقداری به صورت مستقیم به متغیر person2 داده نشده و جلوش مقدار person نوشته شده که چون داخل " " یا ' ' یا ` ` نیست، string هم حساب نمیشه. موتور جاوااسکریپت حدس میزنه preson، یک متغیر در حافظه stack باشه. پس حافظه stack رو بررسی و متغیر person رو پیدا میکنه و مقدار اون متغیر رو برمیداره تا به عنوان مقدار متغیر person2 قرار بده. نکتهای که تو این قسمت باید به اون توجه کنیم اینه که چیزی که به عنوان مقدار متغیر person در حافظه stack ذخیره شده، همون آدرسی است که قبلا دربارهی اون صحبت کردیم. پس درواقع موتور جاوااسکریپت آدرس رو به عنوان مقدار متغیر person برمیداره و به عنوان مقدار متغیر person2 قرار میده و به این ترتیب هر دو متغیر دارای یک آدرس مشترک میشن. یعنی مقادیر دو متغیر person و person2 یک جا ذخیره شدن.
پس اگه مقدار متغیر person رو تغیر بدیم، مقدار متغیر person2 هم تغیر میکنه.
این بار نوبت حافظه heap است که کمی بررسی کنیم اون رو.
حافظه heap دقیقا برعکس حافظه stack است. یعنی این حافظه کنده و طول میکشه تا اطلاعات اون رو خوند. این حافظه اطلاعات بیشتری رو میتونه تو خودش ذخیره کنه و به همین دلیل، دیتاهای reference تو این حافظه ذخیره میشن. دیتا تو حافظه heap به صورت نامنظم و رندم ذخیره میشن و هر دیتا برای خودش یه آدرس داره.
const athlete = { name: "Roger", yearOfBorn: 1981 }; const actor = { name: "Morgan", yearOfBorn: 1937 }; const musician = { name: "Frédéric", yearOfBorn: 1810 };