Chapter 1مقدارها, انواع داده, و عملگرها

Below the surface of the machine, the program moves. Without effort, it expands and contracts. In great harmony, electrons scatter and regroup. The forms on the monitor are but ripples on the water. The essence stays invisibly below.

Master Yuan-Ma, The Book of Programming
Picture of a sea of bits

درون دنیای کامپیوتر، فقط داده‌ (data) وجود دارد. شما می توانید داده‌ها را بخوانید، تغییر دهید، داده‌های جدیدی ایجاد کنید – اما چیزی به جز داده وجود خارجی ندارد. همه‌ی این داده‌ها به شکل دنباله‌ای بلند از بیت ها ذخیره می‌شوند که اساسا به یکدیگر شبیه هستند.

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

به عنوان مثال، می توانیم عدد 13 را به شکل بیت‌ها نشان دهیم. مکانیزم نمایش، شبیه نمایش اعداد دهدهی است؛ اما با این تفاوت که به جای 10 رقم مختلف، شما فقط دو رقم در اختیار دارید که وزن هر کدام با ضریب 2 از راست به چپ افزایش میابد. در اینجا بیت‌هایی که عدد 13 را نشان می دهند به همراه وزن هر رقم در زیر آن آورده شده است.

   0   0   0   0   1   1   0   1
 128  64  32  16   8   4   2   1

بنابراین عدد دودویی مورد نظر 00001101 می‌باشد که معادل رقم‌های غیر صفر آن 8, 4, و 1 می‌باشد که برابر است با 13.

مقدارها

دریایی از بیت‌ها را تصور کنید. اقیانوسی از آن‌ها را. یک کامپیوتر مدرن معمولی دارای بیش از ۳۰ میلیارد بیت در حافظه‌ی فرارش (حافظه‌ی اصلی) است. حافظه‌های غیر فرار(مثل دیسک سخت یا هارد دیسک و شبیه آن) چندین برابر بیشتر و بزرگ تر هستند.

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

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

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

اعداد

مقدارهای مربوط به نوع عدد (number) طبیعتا مقادیر عددی هستند. در یک برنامه جاوااسکریپت، این مقادیر به شکل زیر نوشته می شوند:

13

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

جاوااسکریپت از تعداد بیت ثابتی (64 بیت) برای ذخیره یک عدد استفاده می کند. با این 64 بیت می توان ترکیب‌های بسیار زیادی ساخت و البته که تعداد اعداد متفاوتی که می توان نمایش داد دارای محدودیت است. برای N رقم دهدهی، می توان 10N ( ده به توان N) عدد را نمایش داد. به طور مشابه، برای 64 رقم دودویی، می توان 264 عدد متفاوت را نشان داد که چیزی حدود 18 کوینتیلیون ( عدد 18 و 18 تا صفر جلوی آن) می شود که رقم بسیار بزرگی است.

حافظه‌ی کامپیوتر سابقا بسیار کوچک‌تر بود و برای نمایش اعدا مجبور بودیم از 8 یا 16 بیت استفاده کنیم. در این شرایط به راحتی امکان رخ دادن اتفاقی سرریز (overflow) فراهم بود – عددی تولید شود که با تعداد بیتی که وجود داشت امکان نمایشش نبود. امروزه، حتی کامپیوتر‌هایی که در جیب شما هم جا می شوند دارای حافظه‌های بزرگ هستند بنابراین به راحتی می توانید از قطعه‌های 64 بیتی استفاده کنید و نیازی نیست نگران رخ دادن سرریز باشیم مگر در شرایطی که با اعدادی نجومی و بسیار بزرگ سر و کار داریم.

البته تمامی اعداد صحیح کمتر از 18 کوینتیلیون را نمی توان در جاوااسکریپت نمایش داد. آن تعداد بیت‌هایی که گفته شد، باید اعداد منفی را هم جا بدهند بنابراین یک بیت برای نگه‌داری علامت عدد استفاده می شود. دردسر بزرگ‌تر این است که اعداد غیرصحیح (اعشاری) را نیز باید نشان داد. برای این کار بعضی از بیت‌ها را برای ذخیره‌ی محل قرارگیری نقطه‌ی اعشاری یا علامت ممیز در نظر می گیرند. در واقع بزرگترین عددی صحیحی را که می‌توان ذخیره کرد بیشتر در بازه‌ی 9 کوادریلیون (عدد 9 و 15 صفر) قرار می گیرد که البته هنوز رقم بسیار بزرگی است.

اعداد کسری یا اعشاری را با استفاده از نقطه می نویسند.

9.81

برای اعداد خیلی بزرگ یا خیلی کوچک، همچنین می توایند از روش نمادگذاری علمی استفاده کنید. به این صورت که کاراکتر e (ابتدای واژه‌ی exponent به معنای توان) را به همراه توان عدد در انتهای عدد مورد نظر می نویسیم.

2.998e8

عدد بالا معادل 2.998 × 108 = 299,800,000 می باشد.

محاسبات روی اعداد صحیح (integer) کمتر از بیشینه‌ی ذکر شده (9 کوادریلیون)، همیشه دقیق محاسبه می شوند. متاسفانه، محاسبات روی اعداد اعشاری معمولا این چنین دقیق نیستند. درست مثل عدد پی (Pi) که نمی توان آن را با دنباله‌ای متناهی از ارقام نشان داد، وقتی فقط 64 بیت برای ذخیره‌ی اعداد در اختیار داریم، خیلی از اعداد، بخشی از دقت را در محاسبات از دست می دهند. این قابل قبول به نظر نمی رسد، اما در عمل، مشکل جدی فقط در شرایط خاص رخ می دهد. نکته‌ی مهمی که باید در نظر داشت این است که حواسمان باید به این نبود دقت باشد و با ارقام اعشاری به صورت تقریبی کار کنیم نه به عنوان مقادیر صد در صد دقیق.

حساب

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

100 + 4 * 11

نماد‌های + و * را عملگر می نامند. اولین نماد نماد جمع و دومی برای ضرب استفاده می شود. اگر عملگری بین دو مقدار قرار بگیرد، روی آن‌ها عمل کرده و مقدار جدیدی را تولید می کند.

عبارات بالا آیا به این معناست که عدد 4 را با 100 جمع کن و حاصل را در 11 ضرب نما؟ یا عمل ضرب قبل از جمع انجام می شود؟ همانطور که ممکن است حدس زده باشید، عمل ضرب زودتر انجام می شود. اما درست مثل ریاضیات، می توانید عمل جمع را داخل پرانتز قرار دهید تا ترتیب عوض شود.

(100 + 4) * 11

برای عمل تفریق، عملگر - و برای تقسیم، عملگر / وجود دارد.

زمانی که بدون استفاده از پرانتز از عملگرها استفاده می شود، ترتیبی که برای محاسبه و تقدم آن‌ها استفاده می شود براساس تقدم عملگرهاست. در مثال قبل، مشاهده کردید که عمل ضرب قبل از عمل جمع انجام می شود. عملگر / هم تقدم مشابهی با * دارد. + و - هم تقدم یکسانی دارند. زمانی که چندین عملگر با تقدم مشابه در یک عبارت قرار می گیرند، مثل 1 - 2 + 1، نحوه بکارگیری از چپ به راست خواهد بود: (1 - 2) + 1٫

نگران این قوانین تقدم نباشید. هر زمان که شک داشتید کدام اولویت دارد، از پرانتز استفاده کنید.

یک عملگر حسابی دیگر هنوز مانده، عملگری که احتمالا نتوانید به سرعت کارکرد آن را حدس بزنید. نماد % برای عمل محاسبه باقی مانده استفاده می شود.X % Y به معنای محاسبه‌ی باقی مانده‌ی تقسیم X بر Y است. مثلا 314 % 100حاصلش می شود 14 و 144 % 12، عدد 0 را تولید می کند. تقدم عملگر باقی‌مانده نیز مانند جمع و تقسیم است. شما اغلب برای این عملگر، اصطلاح پیمانه را مشاهده می کنید، اگرچه از نظر فنی همان باقی مانده دقیق تر است.

اعداد خاص

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

دو تای اول Infinity و -Infinity هستند که نماد مثبت و منفی بی‌نهایت می باشند. Infinity - 1 ، همچنان Infinity خواهد بود. زیاد به محاسباتی که بر اساس مقدار Infinity هستند اعتماد نکنید. از نقطه‌نظر ریاضیات، زیاد استوار نیستند و ممکن است باعث تولید نتیجه‌ای بشوند که همان عدد خاص سوم ماست: NaN.

NaN مخفف Not a Number به معنای “غیر عدد” است. اگرچه مقداری برای نوع داده‌ی عدد محسوب می شود. اگر به عنوان مثال، سعی کنید که 0 / 0 (صفر را بر صفر تقسیم کنید) را محاسبه کنید با NaN روبرو خواهید شد یا Infinity - Infinity یا هر عمل حسابی دیگر روی اعداد که نتیجه‌ی آن مشخص و با معنا نباشد.

رشته‌ها

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

`Down on the sea`
"Lie on the ocean"
'Float on the ocean'

می توانید از کاراکتر نقل قول تک، نقل قول جفت یا (`` - backtick) برای مشخص کردن رشته‌ها استفاده کنید البته تا زمانی که برای شروع و پایان رشته از یک علامت یکسان استفاده می کنید.

جاوااسکریپت تقریبا هر مقداری که در داخل علامت‌های نقل قول محصور بشود را رشته در نظر می گیرد یا سعی می کند به رشته تبدیل کند. البته چند کاراکتر ویژه، شرایط متفاوتی دارند. می توانید تصور کنید چقدر سخت خواهد بود که بخواهیم خود علامت نقل قول را بین علامت‌های نقل قول در یک رشته قرار دهیم. کارکترهای خط جدید (کاراکترهایی که پس از فشردن کلید enter به وجود می‌آیند) را نیز بدون “گریز دادن” فقط می توان زمانی در رشته قرار داد که رشته توسط کاراکتر backticks(`) محصور شده باشد.

برای اینکه اینگونه کاراکترها را در یک رشته قرار دهیم، از این روش استفاده می شود: هرگاه درون یک رشته‌‌ی متنی که بین نقل قول محصور شده است، کاراکتر (\) بک اسلش پیدا شود، به این معناست که کاراکتر بعد از آن معنای خاصی دارد و باید طور دیگری تفسیر شود. به این کار گریزدادن (escaping) گفته می شود. کاراکتر نقل قولی که قبل از آن، کاراکتر \ قرار گرفته، دیگر به معنای کاراکتر پایان رشته تفسیر نمی شود بلکه خود بخشی از رشته خواهد بود. اگر بعد از \ کاراکتر n قرار گیرد، به عنوان یک خط جدید تفسیر می شود. به طور مشابه، کاراکتر t بعد از \ ، به معنای tab character خواهد بود. به رشته‌ی زیر توجه کنید.:

"This is the first line\nAnd this is the second"

خروجی واقعی متن بالا به شکل زیر خواهد بود:

This is the first line
And this is the second

مواقعی هم پیش خواهد آمد که بخواهید خود بک اسلش را درون یک رشته نمایش دهید نه به صورت یک کد خاص. در این صورت از دو بک اسلش پشت سر هم استفاده می شود. این کار باعث می شود که یکی از آن‌ها در رشته‌ی نهایی نشان داده شود. مثلا برای اینکه رشته‌ای متناظر با رشته‌ی زیر را نمایش دهید: “A newline character is written like "\n".” در جاوااسکریپت باید به شکل زیر نوشته شود:

"A newline character is written like \"\\n\"."

رشته‌ها نیز بایستی به شکل دنباله‌ای از بیت ها تبدیل شوند تا درون کامپیوتر ذخیره شوند. روشی که جاوااسکریپت برای این کار استفاده می کند بر اساس استاندارد Unicode است. این استاندارد به همه‌ی کاراکترهایی که ممکن است نیاز داشته باشید (شامل کاراکترهای از زبان های یونانی، عربی، ژاپنی، ارمنی و غیره)، عددی را اختصاص می دهد. اگر برای هر کاراکتری عددی داشته باشیم، رشته ها را می توان به وسیله دنباله‌ای از این اعداد توصیف کرد.

و این کاریست که جاوااسکریپت انجام می دهد. اما اینجا یک مشکل وجود دارد: سیستم نمایش جاوااسکریپت از 16 بیت برای هر عنصر رشته استفاده می کند که باعث می شود بتوان تا 216 کاراکتر متفاوت را پوشش داد. اما یونیکد کاراکترهای بیشتری را تعریف می کند که در حال حاضر تقریبا دوبرابر این تعداد است. بنابراین بعضی کاراکترها مثل خیلی از کاراکترهای ایموجی در یک رشته، دو “فضای کاراکتر” را اشغال می کنند. به این نکته در فصل 5 باز خواهیم گشت.

نمی توان عملیات حسابی تقسیم، ضرب یا تفریق را روی رشته‌ها انجام داد، اما عملگر + را می توان استفاده کرد. این عملگر روی رشته‌ها جمع حسابی را انجام نمی دهد، بلکه عمل چسباندن دو رشته را انجام می دهد. کد زیر رشته‌ی "concatenate" را تولید می کند.

"con" + "cat" + "e" + "nate"

می توان روی مقادیر رشته ای عملیاتی را به وسیله توابع مرتبط (متدها) انجام داد که در فصل 4 به آن ها می پردازیم.

رشته‌هایی که به وسیله نقل قول تک یا جفتی نوشته می شوند خیلی شبیه هم عمل می کنند – تنها تفاوت بر می گردد به علامت نقل قولی که بایستی در صورت استفاده با توجه به آن گریز داده شود. رشته‌هایی که با علامت backtick محصور می شوند، که معمولا template literals نامیده می شوند، قابلیت بیشتری دارند. جدا از اینکه می می توان در آن‌ها خطوط رشته را شکست یا خطوط متعدد داشت، می توانند مقادیر دیگر را نیز در خود جاسازی کنند.

`half of 100 is ${100 / 2}`

زمانی که چیزی را داخل${} می نویسید و آن را با backtick محصور می کنید، نتیجه عبارت مورد نظر محاسبه شده، به رشته تبدیل می شود و در جای مورد نظر قرار می گیرد. مثال بالا رشته‌ی “half of 100 is 50” را تولید می کند.

عملگرهای یگانی

همه‌ی عملگرها را با نمادها نشان نمی دهند. بعضی از آن‌ها با حروف معمولی لاتین نوشته‌ می شوند. به عنوان مثال می توان عملگر typeof را ذکر نمود که نوع داده‌ی ورودی خود را به شکل یک رشته برمی گرداند.

console.log(typeof 4.5)
// → number
console.log(typeof "x")
// → string

در مثال‌های کتاب برای اینکه نشان دهیم قصد داریم نتیجه ارزیابی چیزی را ببینیم،‌از دستور console.log استفاده می کنیم. برای اطلاعات بیشتر در باره آن به فصل بعد مراجعه کنید.

دیگر عملگر‌هایی که تا به حال دیده‌ایم بر روی دو مقدار عمل می کردند اما typeof فقط به یک مقدار نیاز دارد. عملگرهایی که به دو مقدار نیاز دارند، عملگرهای دودویی (binary) نامیده می شوند،‌ در حالیکه آن هایی که روی یک مقدار عمل می کنند را عملگرهای یکانی می نامند. عملگر تفریق (-) را می‌توان هم به عنوان یکانی و هم دودویی استفاده کرد.

console.log(- (10 - 2))
// → -8

مقدارهای بولی

گاهی اوقات لازم است تا به وسیله‌ی یک مقدار فقط دو حالت را شناسایی و تمییز دهیم، مثل “yes” و “no” یا “on” و “off”. برای این منظور جاوااسکریپت نوع داده بولی (Boolean) را در نظر گرفته است که فقط دارای دو مقدار است: true و false (که به همین شکل نوشته می شوند).

مقایسه‌ها

یکی از راه‌های تولید مقدار‌های بولی را در مثال زیر می بینیم:

console.log(3 > 2)
// → true
console.log(3 < 2)
// → false

علامت‌های > و < به ترتیب همان نمادهای سنتی برای “بزرگتر است از” و “کوچکتر است از” هستند. آن‌ها عملگرهایی دودویی هستند. در صورت استفاده از آن‌ها منجر به تولید یک مقدار بولی می شود که نشان می دهد آیا true است یا خیر.

رشته‌ها را هم می توان به روشی مشابه مقایسه کرد.

console.log("Aardvark" < "Zoroaster")
// → true

رشته‌ها تقریبا براساس حروف الفبا مرتب می شوند اما نه کاملا به شکلی که در واژه‌نامه می بینید: حروف بزرگ در عمل ،مقایسه از حروف کوچک “کوچک‌تر” محسوب می گردند،‌ بنابراین عبارت "Z" < "a" مقدار true را برمی‌گرداند، وکاراکترهای غیرالفبایی (!,-, و مانند آن‌ها) نیز ترتیب دارند و مقایسه می شوند. در زمان مقایسه‌ی رشته ها، جاوااسکریپت کاراکترهای هر رشته را یک به یک از چپ به راست براساس کدهای یونیکدشان، باهم مقایسه می‌کند.

دیگر عملگرهای مقایسه‌ای به صورت هستند: عملگر=< (بزرگتر مساوی)،=> (کوچکتر مساوی)، == (برابری) و=! (نابرابری).

console.log("Itchy" != "Scratchy")
// → true
console.log("Apple" == "Orange")
// → false

تنهای یک مقدار در جاوااسکریپت وجود دارد که با خودش برابر نیست، و آن NaN است که به معنای “مقدار عددی نیست” می باشد.

console.log(NaN == NaN)
// → false

NaN به این منظور ایجاد شده که نشان دهد نتیجه‌ی محاسبه بی معنا بوده است، و به همین دلیل، با نتیجه‌ی هیچ محاسبه‌ی بی‌معنای دیگری برابر نخواهد بود.

عملگرهای منطقی

عملیاتی نیز وجود دارند که می توانند روی مقدارهای بولی اجرا شوند. جاوااسکریپت از سه عملگر منطقی پشتیبانی می کند: and ، or و not. این عملگرها را می توان برای انجام عملیات منطقی روی عبارات بولی استفاده کرد.

عملگر && نماد and منطقی است. این عملگر دودویی و نتیجه‌ی آن زمانی صحیح (true) است که هر دو عملوند یا مقداری که به آن داده می شود، صحیح (true) باشند.

console.log(true && false)
// → false
console.log(true && true)
// → true

عملگر || نماد or منطقی است. نتیجه‌ی این عملگر زمانی صحیح (true) که یکی از دو مقدار داده شده، صحیح باشد.

console.log(false || true)
// → true
console.log(false || false)
// → false

Not یا نقیض با علامت تعجب (!) نمایش داده می شود که عملگری یکانی است که مقداری را که به آن داده می شود را نقیض می کند ( برعکس می کند) – !true مقدار false را بر می گرداند و !false مقدار true.

زمانی که این عملگرها را با عملگرهای حسابی و دیگر عملگرها ترکیب می کنیم، همیشه واضح نیست که کی لازم است از پرانتزها استفاده کرد. در عمل معمولا می توان با دانستن اینکه در بین عملگرهایی که بررسی کردیم، || دارای کمترین حق تقدم، بعد && و پس از آن عملگرهای مقایسه (>, ==, …) و بعد بقیه عملگرها قرار می گیرند، پیش رفت. با توجه به ترتیب تقدم‌ها به این شکل در عبارتی مثل عبارت پایین به حداقل پرانتز می توان اکتفا کرد.:

1 + 1 == 2 && 10 * 10 > 50

آخرین عملگر منطقی که قصد دارم در باره آن صحبت کنم، نه یکانی است و دودویی، بلکه سه‌تایی (ternary) می باشد و روی سه مقدار عمل می کند. برای نوشتن آن از علامت سوال و دونقطه به شکل زیر استفاده می شود:

console.log(true ? 1 : 2);
// → 1
console.log(false ? 1 : 2);
// → 2

این عملگر را عملگر شرطی می نامند (گاهی اوقات هم همان عملگر سه‌تایی به این دلیل که تنها عملگری است که این ویژگی را در جاوااسکریپت دارد). مقداری که در سمت چپ علامت سوال قرار می گیرد، مشخص می کند که کدام یک از دو مقدار بعدی به عنوان نتیجه برگردانده می شود. زمانی که صحیح (true) ارزیابی شود، مقدار وسطی انتخاب می شود، و هنگامی که false است، آخرین مقدار که در سمت راست قرار دارد، برگردانده می شود.

مقدارهای پوچ

دو مقدار خاص وجود دارد که به شکل null و undefined نوشته می شوند که برای مشخص کردن مقدار‌هایی که درجاوااسکریپت معنایی ندارند استفاده می شوند. آن‌ها خودشان مقدار هستند اما اطلاعات خاصی را حمل نمی کنند.

عملیات زیادی در جاوااسکریپت وجود دارند که مقدار معناداری را تولید نمی کنند ( در ادامه مواردی را خواهید دید) و به این خاطر که بالاخره باید مقداری را برگردانند، undefined را تولید می کنند.

تفاوت معنای دو مقدار undefined و null به خاطر نحوه‌ی طراحی خود جاوااسکریپت است و در بیشتر اوقات باهم تفاوت معنایی خاصی ندارند. اگر شرایطی وجود دارد که باید نگران تفاوت این دو باشید، پیشنهاد می کنم که هر دو را معادل هم در نظر بگیرید و هرکدام را خواستید به جای دیگری استفاده کنید ( در آینده بیشتر به آن می پردازیم).

تبدیل خودکار نوع داده

در مقدمه کتاب، توضیح دادم که جاوااسکریپت برای اینکه هر برنامه‌ای که شما به آن می دهید را تفسیر کند، تلاش بسیاری می کند، حتی برنامه‌هایی که به نظر صحیح نمی آیند. در عبارات زیر این مساله به خوبی نشان داده شده است:

console.log(8 * null)
// → 0
console.log("5" - 1)
// → 4
console.log("5" + 1)
// → 51
console.log("five" * 2)
// → NaN
console.log(false == 0)
// → true

زمانی که یک عملگر، به نوع مقدار غلطی اعمال می شود، جاوااسکریپت با استفاده از مجموعه‌ای از قواعد که اغلب قابل پیش بینی و انتظار نیستند، بی سر و صدا مقدار مورد نظر را به نوعی که می خواهد تبدیل می کند. به این کار، تبدیل خودکار نوع یا type coercion می گویند. بنابراین null در عبارت اول به 0 تبدیل می شود، و "5" در عبارت دوم به 5 ( از رشته به عدد) تبدیل می شود. همچنین در عبارت سوم، + ابتدا سعی می کند که رشته‌ها را بهم الحاق کند قبل از اینکه عمل جمع حسابی را انجام بدهد بنابراین عدد 1 را به "1" ( عدد به رشته) تبدیل می کند.

اگر مقداری را نتوان به شکل واضحی به یک عدد تبدیل کرد‌ (مثلا "five" یا undefined)، مقدار NaN تولید خواهد شد. همچنین عملیات حسابی روی مقدار NaN باعث تولید دوباره‌ی NaN می شود، بنابراین اگر در حین برنامه نویسی متوجه شدید که این مقدار را در جایی که انتظارش را نداشتید،‌ مشاهده کردید، به دنبال تبدیل تصادفی نوع داده بگردید.

زمانی که مقدارهایی از یک نوع داده را با == مقایسه می کنیم، خروجی به راحتی قابل پیش بینی است: اگر دو مقدار مشابه‌ هم باشند، نتیجه صحیح (true) خواهد بود به استثنای مقدار NaN. اما هنگامی‌که نوع داده‌ها متفاوت اند، جاوااسکریپت از یک سری دستورات پییچیده و گیج‌کننده برای انجام مقایسه استفاده می کند. در اکثر موارد، راه‌حل انتخابی تبدیل یکی از مقادیر به نوع مقدار دیگر است. هرچند زمانی که null یا undefined در یک سمت از عملگر قرار می گیرد، زمانی مقدار true تولید می شود که هر دو طرف یا null یا undefined باشند.

console.log(null == undefined);
// → true
console.log(null == 0);
// → false

این رفتار جاوااسکریپت درباره‌ی null و undefined اغلب کاربردی است. می توانید به سادگی با مقایسه‌ی یک مقدار با null با استفاده از عملگر == یا !=، به واقعی و معنادار بودن یک مقدار پی ببرید.

اما برای آزمایش اینکه مقداری دقیقا برابر با false است یا نه، چه باید کرد؟ طبق قوانین مربوط به تبدیل رشته‌ها و اعداد به مقادیر بولی، 0, NaN و رشته‌ی خالی (“”)، به صورت false تفسیر می شوند، درحالی‌که دیگر مقادیر به عنوان true در نظر گرفته می شوند. به همین علت عبارتی مثل 0 == false و "" == false به عنوان true ارزیابی می شوند. برای این گونه موارد، زمانی که این تبدیل خودکار نوع داده را نمی خواهید، می توان از دو عملگر دیگر استفاده کرد: === و !==. عملگر اول بررسی می کند که مقدار دقیقا متناظر با مقدار دیگر باشد، و دومی بررسی می کند که دقیقا متناظر نباشند. بنابراین "" === false ، مقدار ناصحیح(false) را برمی گرداند، همانطور مورد انتظار بود.

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

اتصال کوتاه در عملگرهای منطقی

عملگرهای منطقی && و || از روش به خصوصی برای ارزیابی مقدارهای انواع داده‌ی مختلف استفاده می کنند. ابتدا مقدار سمت چپ عملگر را به نوع بولی تبدیل می کنند تا تصمیم بگیرند که چه کنند و بسته به نوع عملگر و نتیجه تبدیل نوع داده، یا مقدار اولیه سمت چپ را برمی‌گردانند یا مقدار سمت راست را.

عملگر || ، به عنوان مثال، زمانی مقدار سمت چپ عبارت را برمیگرداند که بتوان آن را به true تبدیل کرد و در غیر این صورت مقدار سمت راست را برمیگرداند. این تبدیل همانطور که انتظارش را داشتید برای مقادیر بولی عمل می کند و برای مقادر دیگر انواع داده نیز به شکل مشابهی عمل می کند.

console.log(null || "user")
// → user
console.log("Agnes" || "user")
// → Agnes

با این ویژگی می توان از عملگر || به عنوان روشی برای در نظر گرفتن مقدار پیش‌فرض در عبارت‌ها استفاده کرد. اگر مقداری را داشته باشید که ممکن است تهی باشد، می توانید بعد از آن || به همراه مقداری جایگزین قرار دهید. اگر مقدار اولیه را بتوان به false تبدیل کرد، نتیجه‌ای که دریافت خواهید کرد برابر با مقدار جایگزین خواهد بود. طبق قوانین تبدیل رشته‌ها و اعداد به مقادیر بولی، 0, NaN و رشته‌ی تهی ("") به عنوان false در نظر گرفته می شود، درحالیکه دیگر مقادیر به عنوان true شمرده می شود. بنابراین 0 || -1 مقدار -1 و عبارت "" || "!?" مقدار "!?" را تولید می کند.

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

یکی دیگر از ویژگی‌های مهم این دو عملگر این است که عبارت سمت راست آن‌ها، فقط در صورت نیاز ارزیابی می شود. در مورد مثل true || X، مهم نیست که X چیست، حتی اگر عبارتی است که در صورت اجرا، کار وحشتناکی انجام می دهد – نتیجه عبارت ، true خواهد بود و X اصلا ارزیابی یا اجرا نمی شود. همین قضیه برای false && X نیز صادق است که نتیجه‌ی آن false است و X ارزیابی نمی شود. این‌ کار ارزیابی مدار کوتاه نامیده می شود.

عملگر منطقی (سه‌تایی) نیز به شکل مشابهی کار میکند. عبارت اول، همیشه ارزیابی می شود، اما دومین یا سومین مقدار – مقداری که انتخاب نمی شود – ارزیابی هم نخواهد شد.

خلاصه

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

این مقدار‌ها را می توان با تایپ نامشان (true, null) یا مقدارشان (13, "abc") به وجود آورد. شما می توانید با استفاده از عملگرها، این مقدارها را ترکیب کنید و تغییر دهید. ما عملگرهای دودویی را برای عملیات حسابی (+, -, *, /, و %)، عملگر الحاق رشته (+)، عملگرهای مقایسه (==, !=, ===, !==, <, >, <=, >=)، منطقی (&&, ||)، همچنین چندین عملگر یکانی (- برای منفی کردن یک عدد، ! برای نقیض منطقی، و typeof برای فهمیدن نوع داده‌ی یک مقدار) و عملگر سه‌تایی (?:) برای انتخاب یکی از دو مقدار بر اساس مقدار سوم را در این فصل مشاهده نمودیم.

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