نوعهای primitive و object
در جاوااسکریپت، هر مقداری یا از یک نوع primitive است و یا یک object است. نوعهای primitive نوعهایی هستند که
مقادیر آنها شامل فقط یک چیز هستند (یک عدد، یک رشته و ...) اما نوع object که تنها نوع non-primitive در
جاوااسکریپت است، میتواند شامل اعضای چندمقداری باشد. جدول زیر شامل یک معرفی کوتاه از ۷ نوع primitive و نوع
object است.
نوع داده |
توضیح |
number |
مطابق انتظار، این نوع داده برای مقادیر عددی در نظر گرفته شده است.
|
bigint |
این نوع برای نمایش اعداد صحیح خیلی بزرگ که خارج از بازهی ±(253-1) هستند، تعریف
شده است.
|
string |
این نوع برای مقادیر متنی در نظر گرفته شده است.
|
boolean |
این نوع داده شامل دو مقدار true و false است.
|
null |
یک نوع خاص است که تنها شامل یک مقدار null است که نشانگر مقدار تهی است.
|
undefined |
یک نوع خاص است که تنها شامل یک مقدار undefined است که به متغیری اختصاص داده میشود که تعریف شده اما
مقداری ندارد.
|
object |
هر مقداری که به یکی از ۷ نوع primitive تعلق نداشته باشد، یک object است.
|
symbol |
یک مقدار از این نوع، شناسهی یکتایی است که به یک object اختصاص داده میشود.
|
در طول این دوره با جزئیات مربوط به این نوعها آشنا خواهیم شد اما فعلاً یک معرفی مقدماتی از هر یک از آنها
ارائه میدهیم.
نوع number
بر خلاف برخی زبانهای دیگر که دارای چندین نوع عددی هستند، در جاوااسکریپت تنها یک نوع number برای مقادیر عددی
در نظر گرفته شده است. یعنی هر مقدار عددی اعم از صحیح و اعشاری دارای نوع number است. در
ترمینال، عبارت node
را وارد کنید تا مفسر Node.js آمادهی تفسیر دستورات جاوااسکریپتی شما شود و سپس، دستورات زیر را آزمایش کنید.
> typeof(8000)
'number'
> typeof(3.14)
'number'
> let e = 2.71828;
> typeof(e)
'number'
عملگر typeof نوع مقداری که دریافت کرده را برمیگرداند.
در انتهای این درس، نکاتی در ارتباط با این عملگر بیان خواهد شد.
اما نوع number علاوه بر مقادیر عددی، دو مقدار خاص دیگر هم دارد که عبارتند از: Infinity و
NaN.
- مقدار Infinity معادل مفهوم بینهایت در ریاضیات است؛ یک مقدار خاص که از هر عددی بزرگتر است. مقدار
-Infinity نیز نشانگر بینهایتِ منفی است.
- مقدار NaN یا Not a Number مقدار خاصی است که نشانگر یک خطای محاسباتی است و معمولاً در اثر یک عمل ریاضی
نامعتبر تولید میشود. با کمی تفاوت مختصر، میتوان این مقدار را معادل مفهوم مبهم (indeterminate) در ریاضیات
دانست.
در اینجا چند عبارت محاسباتی را با استفاده از عملگرهای جمع (+)، تفریق (-)، ضرب (*)، تقسیم (/) و توان (**)
آزمایش کردهایم.
> 1 / 0
Infinity
> -2 / 0
-Infinity
> 0 / 0
NaN
> Infinity * 2
Infinity
> Infinity * Infinity
Infinity
> Infinity – Infinity
NaN
> Infinity / Infinity
NaN
> Infinity + Infinity
Infinity
> 1 ** Infinity
NaN
> Infinity ** 0
1
> "Hi" / 5
NaN
> NaN * 2
NaN
> NaN + 1
NaN
> 0 ** 0
1
> NaN ** 0
1
همانطور که میبینید، در اکثر موارد، نتیجه با آنچه در ریاضیات دیدهایم، مطابقت دارد. اما تفاوتهایی هم وجود
دارد. مثلاً در ریاضیات 0 ** 0 مبهم ارزیابی میشود اما در جاوااسکریپت برابر با 1 تعیین میشود. در واقع، در
جاوااسکریپت هر مقدار عددی به توان صفر برابر با 1 خواهد بود و هیچ استثنایی هم ندارد. حتی NaN که وجودش در هر
عمل محاسباتی منجر به تولید خود NaN میشود، وقتی به توان صفر برسد، نتیجهی 1 را تولید میکند.
نوع bigint
در جاوااسکریپت، نوع number قادر نیست که اعداد بزرگتر از 253 - 1 و
کوچکتر از
-(253 - 1) را به طور امن نمایش دهد. در واقع،
نوع number میتواند اعداد صحیح بزرگتر را هم ذخیره کند اما در مورد اعداد خارج از بازهی
امن
±(253 - 1) این کار را با خطایی
موسوم به خطای دقت یا Precision Error انجام میدهد. چون همهی ارقام در 64 بیتی که برای مقادیر از نوع number
در نظر گرفته شده جا نمیشوند، بنابراین یک تقریب از عدد ذخیره میشود.
برای مثال، دو عدد زیر که خارج از بازهی امن ±(253 - 1) هستند، یکسان در نظر گرفته
میشوند.
> console.log(9007199254740991 + 1);
9007199254740991
> console.log(9007199254740991 + 2);
9007199254740991
در اکثر موارد، نیازی به اعداد خارج از بازهی امن نداریم اما با این حال، مواردی هم هست که واقعاً به اعداد
بزرگتر نیاز پیدا میکنیم. برای مثال، اگر بخواهیم بازههای زمانی را بر حسب میکروثانیه ذخیره کنیم، به اعداد
خیلی بزرگ نیاز پیدا میکنیم. با هدف پوشش این دست موارد، نوع bigint در ES6 به این
استاندارد اضافه شد.
برای تولید یک مقدار bigint کافیست حرف n را به انتهای عدد مورد نظر اضافه کنیم.
> const bigNumber = 1234567890123456789012345678901234567890n;
> typeof(bigNumber)
'bigint'
جزئیات مربوط به bigint در آینده ارائه خواهد شد.
نوع string
نوع string برای نمایش مقادیر متنی یا رشتههای متنی (text strings) تعریف شده است.
رشتههای متنی را باید درون
کوتیشن قرار داد و در جاوااسکریپت میتوان از سه نوع کوتیشن استفاده کرد:
- کوتیشن تکی یا Single Quote: مانند ‘Hello’
- کوتییشن جفتی یا Double Quote: مانند “Hello”
- کوتییشن بکتیک یا Backtick Quote: مانند `Hello`
کوتیشنهای تکی و جفتی کوتیشنهای ساده هستند و عملاً تفاوتی با هم ندارند. البته اگر در رشتهی مورد نظر،
کاراکتر آپستروف وجود داشته باشد، بهتر است رشته را در کوتیشن جفتی وارد کنیم تا مشکلی به وجود نیاید.
اما کوتیشن Backtick قابلیتهای بیشتری دارد. یکی از مهمترین این قابلیتها این است که میتوانیم متغیرها و
عبارات (expressions) را با استفاده از سینتکس ${…} درون رشتهها جاسازی کنیم. مثال زیر را ببینید.
datatypes.js
let name = "John";
console.log(`Hello, ${name}!`);
console.log(`the result is ${1 + 2}`);
عبارت درون ${…} ارزیابی شده و نتیجه تبدیل به بخشی از رشته میشود. توجه داشته باشید که این کار فقط
در مورد
کوتیشنهای ایجاد شده با Backtick ممکن است و کوتیشنهای تکی و جفتی چنین قابلیتی ندارند.
رشتههای متنی و نوع string را هم به طور مفصل در فصلهای آینده بررسی خواهیم کرد.
نوع boolean
نوع boolean تنها دارای دو مقدار true و false است. این نوع برای ذخیرهی مقادیر دو حالته
که میتوانند درست یا
غلط باشند، کاربرد دارد.
datatypes.js
let nameFieldChecked = true;
let ageFieldChecked = false;
نتیجهی حاصل از یک عمل مقایسهای یک مقدار boolean است. دستورات زیر را آزمایش کنید.
> 4 > 1
true
> 3 >= 4
false
> 2 == 4 / 2
true
نوع null و undefined
مقدار خاص null به هیچیک از نوعهای بالا تعلق ندارد، بلکه متعلق به نوعی است به نام null
که همین یک مقدار را
دارد. در جاوااسکریپت بر خلاف آنچه که شاید در برخی زبانهای دیگر دیده باشید، null یک اشارهگر (pointer) به یک
شیء ناموجود یا null pointer نیست، بلکه فقط یک مقدار است که بیانگر نبود مقدار، تهیبودن یا ناشناخته بودن
مقدار است.
datatypes.js
مقدار undefined نیز مثل null یک مقدار خاص است که نوع خودش را دارد. با وجود شباهتی که بین null و undefined
وجود دارد، باید بدانید که undefined از عدم تخصیص مقدار حکایت میکند. یعنی اگر متغیری را تعریف کنیم ولی
مقداری به آن ندهیم، دارای مقدار undefined خواهد بود.
datatypes.js
let age;
console.log(age);
اینکه مقدار undefined را به طور مستقیم به یک متغیر اختصاص دهیم، اگرچه از نظر فنی ممکن است اما کار رایجی نیست
و دلیل خوبی برای آن وجود ندارد. اما در مورد null همانطور که بعداً خواهید دید، مواردی وجود دارد که این کار را
انجام میدهیم.
نوع object و symbol
نوعهایی که تا الان دیدیم، نوعهای primitive نامیده میشوند، چون مقادیر آنها فقط میتوانند شامل یک چیز (یک
عدد، یک رشتهی متنی یا هر چیز دیگر) باشد. اما object یک نوع Non-primitive است که برای
ذخیرهی مجموعهای از
دادهها در یک متغیر کاربرد دارد. در جاوااسکریپت، هر مقدار پیچیدهای که به یکی از ۶ نوع بالا (و symbol) متعلق
نباشد، یک object است. در مورد نوع object در فصل چهارم مطالب لازم بیان
خواهد شد.
symbol هم نوعی است که برای ایجاد شناسههای یکتا برای object کاربرد
دارد. ما در اینجا برای کامل بودن بحث
مربوط به نوعهای داده از نوع symbol نام بردیم اما طبیعتاً بررسی آن باید به بعد از بررسی
object موکول شود.
عملگر typeof
عملگر typeof نوع عملوند (operand) خود را برمیگرداند. دستورات زیر را اجرا کنید و نتیجه
را ببینید.
> typeof undefined
'undefined'
> typeof 0
'number'
> typeof 10n
'bigint'
> typeof true
'boolean'
> typeof "foo"
'string'
> typeof Symbol("id")
'symbol'
> typeof Math //(1)
'object'
> typeof null //(2)
'object'
typeof console //(3)
'function'
در مثال بالا، سه دستور پایانی به توضیحاتی نیاز دارند:
-
Math نام یک شیء built-in است که اعمال ریاضی متنوعی را فراهم میکند. بعداً جزئیات مربوط
به آن را خواهیم
دید.
-
عملگر typeof نوع null را object برگردانده است. با وجود تفسیرهای
غیردقیقی که سعی در توجیه این امر دارند
اما حقیقت این است که این فقط یک اشتباه مربوط به نسخههای ابتدایی ES است که به خاطر حفظ سازگاری اصلاح نشده
است. اما قطعاً null یک object نیست، بلکه مقدار خاصی است از نوع خودش.
-
به دلیلی مشابه آنچه در مورد null گفتیم، عملگر typeof نوع console
را function گزارش میکند که هم درست است
و هم غلط. console واقعاً یک تابع (function) است اما مسئله این است که ما از عملگر typeof انتظار داریم یک
نوع برگرداند. این دست موارد، منطقاً اشتباه محسوب میشوند اما شهوداً مشکلی ندارند.
نکتهی پایانی در مورد عملگر typeof به استفاده یا عدم استفاده از پرانتزها برمیگردد. در
یکی از مثالهای درس
جاری، ما از عملگر typeof به صورت typeof(8) استفاده کردیم اما در مثال
اخیر از این عملگر بدون پرانتز استفاده
کردیم. داستان چیست؟
typeof یک عملگر است نه یک تابع و بنابراین، به پرانتز نیازی ندارد. اما اگر هم از پرانتز
استفاده کنیم، مشکلی
پیش نمیآید، چون مفسر در اینجا پرانتزها را نه از نوع پرانتزهای تابع بلکه از نوع پرانتزهایی در نظر میگیرد که
برای گروهبندی محاسبات ریاضی به کار میروند.