چرا جاوا اسکریپت خنگ به نظر می‌رسد!

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

اما داستان چیه

بهتره برای شناخت و حل این چالش کمی عمیق‌تر موضوع رو بررسی کنیم از جایی که جاوا اسکریپت تصمیم گرفت منعطف باشه و مثل C++ یا هم قبیله‌هاش سختگیر و خشک نباشه.
واسه همین اون تصمیم گرفت از نوع داده سست یا weak typing یا همون dynamic typing پشتیبانی کنه. این سبک معمولا به عنوان یک مزیت برای انعطاف پذیری برنامه‌ عنوان میشه. در این حالت برای متغییر نوع داده مهم نیست و هر مقداری رو در طول پروسه برنامه می‌توانیم در اون مقدار‌دهی کنیم. به عبارتی متغییر‌ها ظر‌ف‌هایی هستند که هر نوع داده‌ای را هر وقت بخواهیم می‌توانیم در آن بریزیم بدون این که به خطا و مشکلی بخوریم یا این که بعد از تبدیل نوع داده در طول برنامه مجبور باشیم تا یک متغییر جدید برای نوع داده جدید بوجود آمده بسازیم.

این مثال رو ببینید (بهتره کد‌ها رو کپی کنید و در کنسول مرورگر اجرا کنید و نتیجه رو ببینید):

var amount = 99.99;
amount = amount * 2;
console.log(amount); // 199.98
// convert `amount` to a string, and
// add &quot$&quot on the beginning
amount = &quot$&quot + String(amount);
console.log(amount); // &quot$199.98&quot

در ابتدا amount داده‌ای از نوع Number داشت و در خط یکی مونده به آخر طی عملیات‌هایی داده‌ از نوع String شد. این در نوع داده سست یا پویا مجاز هست حالا فرض کنید اگر جاوا اسکریپت از نوع داده سخت یا Static typing که برخی موارد به اون type enforcement هم گفته میشه پشتیبانی می کرد در خط یکی مونده به آخر باید یک متغییر جدید مثلا amountAsString تعریف می‌شد تا داده تغییر یافته رو نگهداری می‌کرد و دیگه نمی‌شد داده رو توی amount که جنس عددی میگیره ریخت.


تبدیل نوع داده خودکار ضمنی یا همون implicit coercion

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

در راستای همین انعطاف پذیری جاوا اسکریپت در دل خود و دور از چشم ما قابلیتی رو پشتیبانی میکنه تحت عنوان تبدیل نوع داده خودکار ضمنی یا همون implicit coercion. در JS شما برای عملیات‌های ریاضی باید جنس داده‌هاتون عددی باشه و اگر بخواین چیزی رو روی صفحه نمایشگر نشون بدید باید از نوع String باشه و وقتی دارین شرط رو چک می‌کنید باید یک داده بولین (true / false) باشه.

در راستای همین انعطاف پذیری JS وقتی نوع داده برای عملیاتی معتبر نباشه خودش سعی می‌کنه به نوع داده‌ای که می‌تونه معتبر باشه تبدیل نوع انجام بده و تا حد امکان سخت نگیره و خطا نده. مثلا وقتی شما یک رشته رو به یک شرط بدید اون رو به بولین تبدیل می‌کنه و نمیگه داده معتبر نیست و باید بولین باشه. در JS رشته‌ی تنهایی که خالی هست به False و دارای کاراکتر به True تعبیر میشه:

if (&quot this is sample test &quot)
    alert(1000);

همچنین یک اتفاق دیگه هم در کد بالا می‌افته ولی شما متوجه اون نمی‌شید. وقتی alert اجرا میشه چون نمایش یک داده در صفحه است باید 1000 که یک عدد است به رشته تبدیل بشه این کار رو JS اتوماتیک انجام میده. به همه این تبدیل‌های خودکاری که اتفاق می‌افته تبدیل نوع داده خودکار ضمنی یا همون implicit coercion گفته میشه.

از طرفی این کار بسته به محل و شرایط اتفاق می افته نه همیشه و همه جا به یک صورت.مثلا رشته غیر خالی اگر به تنهایی در شرط بیاد به true تعبیر می‌شود ولی اگر در یک عملیات مقایسه‌ای بیاد به عدد تبدیل میشه و اگر رشته قابل تبدیل به عدد نباشه NaN میشه!

>>> &quot0&quot == false
true

>>>  if (&quot0&quot) console.log(&quot it's true &quot)
it's true 

هر چیزی یه خوبی داره یه بدی داره

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


یک مثال دیگه:

I>>> &quot0&quot == 0
true

>>> 0 == [ ]
true


>>>  &quot0&quot == [ ]
false


راه حل

راه حل این مشکل استفاده از شرط‌های قطعی و تبدیل نوع‌های دستی هست. در واقع هر کس این اصول رو یاد گرفت و باش مشکلی نداشت می‌تونه باش کار کنه ولی کسایی که نمی‌تونن JS دستشون رو نبسته و این امکان رو گذاشته که از شرط قطعی و تبدیل اجباری استفاده کنن تا شبیه زبان‌های نوع داده سخت بشه. دو مثال بالا بعد از تغییرات سختگیرانه:

>>> &quot0&quot === false
false


>>> if (   Number(&quot0&quot)  !== 0   )    console.log(&quot it's true &quot)
// no result

یک مثال دیگه:

I>>> &quot0&quot === 0
false

>>> 0 === [ ]
false


>>>  &quot0&quot === [ ]
false


این مطالب هم می‌تونه واست سودمند باشه:

https://virgool.io/JavaScript8/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%AF%D9%87%D9%86%D8%AF%D9%87-front-end-%DB%8C%D8%A7-%DA%86%DB%8C-euhuy45ijfdf
https://virgool.io/programmers-revolution/%D8%A7%D8%B3%D8%AA%D8%A7%D8%B1%D8%AA%D8%A2%D9%BE-%DB%8C%D8%A7-%D9%82%D8%AA%D9%84%DA%AF%D8%A7%D9%87-%DA%A9%D8%A7%D8%B1%D9%85%D9%86%D8%AF%D8%A7%D9%86-whtphuslrdju