درآمدی بر زبان برنامه نویسی عجیب و غریب ولی همه‌گیر جاوا اسکریپت – ۱

shape
shape
shape
shape
shape
shape
shape
shape

سال 1995، آقایی به نام Brendan Eich تو شرکت  Netscape Communications زبان برنامه نویسی جدیدی را با الهام گرفتن از زبان‌های java و Scheme و Self، به نام JavaScript طی ده روز کاری ایجاد شد. چرا؟ چون شرکت Netscape به دنبال ارائه زبانی بود که بتواند وب را داینامیک کند. مثلا تا قبل از این تصمیم، برای چک کردن اعتبار ورودی‌های فرم، ورودی‌ها به سمت سرور ارسال می‌شد و در آنجا پس از اعتبارسنجی، پاسخی برای کاربر ارسال می‌شد. از مدتی پیش از این تصمیم، Netscape با شرکت نرم‌افزاری و سخت‌افزاری Sun شروع به همکاری کرد تا از زبان Java در مرورگر استفاده کند. با وجود زبان java و هزینه بر بودن توسعه دهندگان این زبان، این شرکت دنبال ایجاد زبان اسکریپتی بود که برنامه‌نویسان با تعداد بیشتر و طراحان وب بتوانند، با استفاده از این زبان، محتوای وب را با استفاده از عکس و پلاگین و Java applet ایجاد کنند. پس توسعه‌دهندگان زبان java کامپوننت‌هایی را ایجاد می‌کردند تا توسعه‌دهندگان زبان اسکریپتی جدید، بتوانند با به هم چسباندن این کامپوننت‌ها محصول نهایی را ایجاد کنند. به این توسعه دهندگان به اصطلاح glue programmers و به زبان مورد استفاده این توسعه دهندگان glue language گفته می‌شود.

در نتیجه تصمیم بر این شد تا زبان اسکریپتی جدید، دارای سینتکسی شبیه به زبان java داشته باشد که باعث شد از زبان های اسکریپتی موجود مانند Perl, Python, TCL, or Scheme استفاده نشود. که به همین منظور Netscape به یک پروپوزال نیاز داشت. پس Eich طی ده روز این زبان را ایجاد کرد.

شرایط خاص ایجاد این زبان شامل فشردگی زمان ایجاد زبان، تصور جدی نبودن توسعه زبان برای وب، با سرعت پیش رفتن وب و عدم امکان توقف برای توسعه، ناآشنا بودن طراحی زبان برای توسعه‌دهندگان، همگی باعث ایجاد احساس تنفر از این زبان شد. اکنون پس از گذشت 25 سال از اختراع این زبان، طبق گزارش این لینک زبان جاوا اسکریپت در سه ماه سوم 2019 بیشترین میزان تغییرات را در کدهای public repository (مخازن عمومی) داشته است.

عبارات عجیب در زبان جاوا اسکریپت

در ادامه مواردی از عجایب این زبان خواهیم دید:


[] == ![]; // -> true

true == []; // -> false
true == ![]; // -> false

false == []; // -> true
false == ![]; // -> true

!!"false" == !!"true"; // -> true
!!"false" === !!"true"; // -> true

برای توضیح رفتار اینگونه عبارت به فایل این لینک مراجعه کنید.

جاوا اسکریپت چگونه کار میکند

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

موتور جاوا اسکریپت

یکی از محبوب ترین موتور های زبان جاوا اسکریپت، موتور v8 گوگل است که در مرورگر گوگل کروم و Node.js استفاده می‌شود. موتور شامل دو بخش اصلی است:

  • پشته حافظه (memory heap): این بخش جایی است که که تخصیص حافظه (memory allocation) رخ می‌دهد.
  • پشته فراخوانی (call stack): در این بخش علاوه بر اجرای کد، پشته (stack) هم قرار دارد.

زمان اجرا

یک سری از api ها در مرورگرها وجود دارند که بسیاری از توسعه دهندگان جاوا اسکریپت از آن استفاده می‌کنند. با این حال این api ها توسط موتور ارائه نشده است. اینجاست که موضوع یکم پیچیده می‌شود.

پس علاوه بر موتور، یک سری Web API ها وجود دارند که توسط مرورگر در اختیار توسعه دهنده قرار میگیرد. و علاوه بر أن پشته callback و event loop هم وجود دارند.

پشته فراخوانی یا call stack

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


function multiply(x, y) {
return x * y;
}

function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);

وقتی موتور این کد را اجرا میکند، در ابتدا call stack خالی می‌باشد:

هر ورودی در این پشته فریم پشته (stack frame) خوانده می‌شود. به این ترتیب، هر وقت خطایی رخ دهد، محل دقیق رخ دادن خطا مشخص می‌شود.



function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}

function bar() {
foo();
}

function start() {
bar();
}
start();

اگر این قطعه کد در گوگل کروم اجرا شود پیغام خطای زیر را دریافت خواهید کرد:

(نام فایل این قطعه کد foo.js می‌باشد)

زمانی که پشته بیش از حد پر شود، پیغام خطای Blowing the stack نمایش داده خواهد شد. مانند قطعه کد زیر که به صورت بازگشتی و بدون حالت پایه، فراخوانی می‌شود.


function foo()
 { foo(); } 
foo();

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

در نقطه معینی، تعداد فراخوانی های تابع در call stack بیش از حد اندازه واقعی call stack می‌شود و مرورگر با نمایش پیغام زیر ادامه اجرا کد را متوقف می‌کند.

اجرای کد با استفاده از یک ترد ساده به نظر می آید و دیگر مجبور نیستید با مشکلاتی که در رویه های چند ترد ایجاد می‌شود، روبرو شوید. به عنوان مثال deadlock. اما اجرای کد با استفاده از یک ترد محدودیت دارد. از آنجایی که فقط یک call stack  وجود دارد، پس وقتی تابعی کند اجرا شود چه اتفاقی می‌افتد؟

در پست آینده با معرفی asynchronous callbacks به این سوال پاسخ خواهیم داد.

نویسنده : محمد نبی خانی

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *