مقدمه
در این درس، قصد داریم در مورد ویژگیهای کلیدی زبان برنامهنویسی جاوااسکریپت صحبت کنیم.
ویژگیهای مورد بحث ما مواردی هستند که بین زبانهای برنامهنویسی مختلف تمایز ایجاد
میکنند. به عنوان نمونه، سطح انتزاع (abstraction level) یکی از این ویژگیهاست که باعث به
وجود آمدن مفهوم زبانهای سطح بالا و سطح پایین شده است. البته ما با دو گروه زبانهای سطح
پایین و سطح بالا مواجه نیستیم، بلکه با یک طیف از پایینترین سطح (ماشین) تا بالاترین سطح
(انسان) مواجه هستیم. ویژگی کلیدی دیگر، سیستم نوع (type system) هر زبان است که باعث تفکیک
زبانهای برنامهنویسی به دو گروه زبانهای دینامیک و استاتیک میشود. ویژگی قابل ذکر دیگر،
روش ترجمه (parsing method) است که رویکردی است که برای تبدیل کدهای یک زبان به کدهای ماشین
به کار گرفته میشود. از این حیث نیز زبانهای برنامهنویسی یا کامپایلری هستند و یا تفسیری
و یا ترکیبی از هر دو. در ادامه، هر یک از ویژگیهای مذکور را در زبان جاوااسکریپت بررسی
میکنیم.
جاوااسکریپت یک زبان سطح بالاست
کامپیوترها از قطعات سختافزاری الکترونیک ساخته میشوند و لذا راه برقراری ارتباط مستقیم با
یک کامپیوتر، ارسال سیگنالهای الکتریکی است. سادهترین سیگنالهایی که توسط کامپیوترها
قابل درک است، سیگنالهای on و off هستند و بنابراین، الفبای زبان کامپیوترها تنها از دو
حرف تشکیل میشود که از نمادهای 0 و 1 برای نمایش این دو حرف استفاده میشود و به همین دلیل
است که ما زبان کامپیوترها را اعداد باینری (اعداد در مبنای 2 که تنها از ارقام 0 و 1 تشکیل
میشوند) میدانیم. کامپیوترها دستورات ما را که Instruction یا دستورالعمل نامیده میشوند،
دریافت کرده و آنها را اجرا میکنند.
منظور از سطح یک زبان برنامهنویسی، سطح انتزاع آن از سختافزار و ماشین است. سختافزار هر
کامپیوتر از روی یک معماری (architecture) ساخته میشود و هر معماری شامل مواردی از جمله یک
مجموعه دستورالعمل (instruction set) است که تعیینکنندهی زبان ماشین کامپیوتر است. با
دانستن معماری یک کامپیوتر و اطلاع از زبان ماشین آن، میتوان بدون هیچ واسطهای مستقیماً
برای یک کامپیوتر برنامه نوشت. این شیوه را برنامهنویسی ماشین میگویند و در گذشته تنها
راه برنامهنویسی برای کامپیوترها بود. طبیعتاً برنامهای که برای کامپیوتری با یک معماری
مسخص نوشته میشود، لزوماً روی کامپیوترهایی که از معماری متفاوتی بهره میبرند، قابل اجرا
نیست. از آنجایی که زبان کامپیوترها زبان اعداد و آن هم اعداد باینری (اعداد در مبنای دو)
است، دستورات ماشین به صورت رشتههایی از صفر و یک هستند.
با هدف سادهسازی فرایند برنامهنویسی، برای هر دستورالعمل باینری مربوط به یک ماشین، یک
عبارت معادل به زبان انگلیسی در نظر گرفته شد و به این ترتیب، زبانهای اسمبلی پدید آمدند.
در نهایت، برنامهی اسمبلی نوشته شده توسط ابزاری به نام اسمبلر (assembler) به زبان ماشین
ترجمه میشد. پس در این روش، ما به جای ماشین برای اسمبلر برنامه مینویسیم و اسمبلر کدهای
ما را به زبان ماشین ترجمه میکند. زبانهای اسمبلی اگر چه کار برنامهنویسی را سادهتر
کردند اما همچنان متکی به رویکرد ماشین بودند و در واقع، هنوز برنامهنویس باید مانند ماشین
فکر میکرد و دستوراتی را برای اجرا به صورت پشت سر هم مینوشت.
در ادامه، زبانهای سطح بالا مانند Fortran و LISP و بعداً C پدید آمدند که به
برنامهنویس امکان میدادند از عبارات انگلیسی و ریاضی و از یک رویکرد نزدیک به زبانهای
انسانی برای نوشتن برنامه استفاده کنند و کار ترجمهی کدها را به نرمافزارهای سیستمی خاصی
به نام کامپایلر و مفسر بسپارند.
در معماری کامپیوتر و برنامهنویسی، ماشین در پایینترین سطح و انسان در بالاترین سطح قرار
دارد. هر چقدر از زبان ماشین فاصله میگیریم، لایههای اضافی بیشتری بین برنامهنویس و
کامپیوتر قرار میگیرند که از طرفی باعث سادهتر شدن برنامهنویسی میشوند و از طرفی برای
ترجمهی کدها به زبان ماشین باید کار بیشتری انجام شود و اصطلاحاً سربار (overhead) بیشتری
برای برنامه ایجاد میشود.
بنابراین، زبانهای سطح بالاتر به زبان انسان نزدیکتر بوده و از سطح انتزاع بیشتری نسبت به
سختافزار برخوردارند. به این ترتیب، روشن است که همهی زبانهای سطح بالا نیز در یک سطح
قرار ندارند. در حقیقت، هر چقدر زبانی به زبان انسانی نزدیکتر باشد و یا به عبارت دیگر از
انتزاع بیشتری نسبت به زبان سختافزار برخوردار باشد، سطح بالاتر نامیده میشود. به عنوان
مثال، زبانهای جاوااسکریپت و C هر دو از زبانهای سطح بالا هستند اما جاوااسکریپت نسبت به
زبان C از سطح بالاتری برخوردار است. هر چقدر سطح انتزاع زبانی بالاتر باشد، برنامهنویسی
با آن زبان سریعتر و راحتتر است و به عبارتی چنین زبانی ارگونومی بهتری دارد اما در عوض،
برنامههای نوشته شده به زبانهایی با سطح انتزاع پایینتر از کارایی (performance) بالاتری
برخوردارند و سرعت اجرای آنها بیشتر است.
مفهوم Trade-off
در معماری و طراحی کامپیوتر، ساخت یک زبان برنامهنویسی، تولید یک اپلیکیشن و به طور کلی
در علوم مرتبط با کامپیوتر در بسیاری از مواقع ناچاراً باید به یک مصالحه (trade-off)
تن بدهیم. این مصالحهها از وجود ویژگیهای متعارض ناشی میشوند، یعنی ویژگیهایی که
بهبود یکی از آنها باعث افت دیگری میشود. یکی از مواردی که در ساخت یک زبان
برنامهنویسی نیاز به مصالحه دارد، تعیین سطح انتزاع زبان است. با افزایش سطح انتزاع،
زبان تولید شده ارگونومیکتر بوده و سرعت توسعه با چنین زبانی بالاتر است اما در عوض،
سرعت اجرای برنامههای تولید شده با این زبان پایینتر خواهد بود و امکان کنترل جزئیات
سطح پایین نیز وجود ندارد.
جاوااسکریپت یک زبان تفسیری است
زبانهای سطح بالا را از نظر روشی که برای ترجمهی کدهای منبع به کدهای ماشین به کار
میگیرند، میتوانیم در دو گروه کلی زبانهای کامپایلری یا کامپایلشده (compiled) و
زبانهای تفسیری یا تفسیر شده (interpreted) قرار دهیم.
زبانهای کامپایلری کدهای نوشته شده را قبل از اجرا و در زمان ساخت برنامه کامپایل میکنند و
به کد باینری تبدیل میکنند. بنابراین، برای کدنویسی با استفاده از اینگونه زبانها به یک
کامپایلر نیاز داریم اما پس از کامپایل کدها و تولید فایل باینری، این فایل قابلیت اجرا
پیدا میکند و اصطلاحاً پرتابل (portable) است و میتوان آن را روی هر سیستمی و بدون نیاز
به هیچ ابزاری اجرا کرد. زبانهایی مانند C و C++ کامپایلری هستند.
اما در مورد زبانهای تفسیری، ترجمه یا تفسیر و اجرای کدها در تنها یک مرحله و در زمان اجرا
انجام میشود و کدها به همان صورتی که نوشته شدهاند، به مفسر تحویل داده میشوند.
بنابراین، برای اجرای کدهای نوشته شده به این زبانها یک مفسر نیاز است. زبانهایی مانند
جاوااسکریپت، روبی و پایتون زبانهای تفسیر شده هستند. پس، ما نمیتوانیم یک فایل .js یا
.rb یا .py را بدون استفاده از یک مفسر اجرا کنیم.
کامپایلر JIT در جاوااسکربپت
مفسرهای مدرن جاوااسکریپت از تکنیکی به نام کامپایل Just-in-time که به اختصار JIT نامیده
میشود، استفاده میکنند. کامپایل JIT روشی است که مفسرهای جاوااسکریپت برای افزایش
کارایی (performance) اپلیکیشنها به کار میگیرند.
جاوااسکریپت یک زبان دینامیک است
یک طبقهبندی دیگر برای زبانهای برنامهنویسی میتواند بر اساس سیستم نوع یا Type System
صورت پذیرد. از این حیث، زبانهای برنامهنویسی در دو گروه زبانهای استاتیک و دینامیک یا
به بیان دقیقتر Statically typed و Dynamically typed جای میگیرند.
در زبانهای استاتیک، به طور طبیعی تعریف یک متغیر باید با اعلان نوع آن متغیر همراه باشد و
متغیر مورد همواره از همان نوعی خواهد بود که در هنگام تعریف تعیین شده است و امکان تغییر
نوع آن در طول برنامه و اعطای مقادیر از نوعهای دیگر به آن وجود ندارد. در اینگونه زبانها
چنانچه بخواهیم مقداری از یک نوع را به متغیری از نوع دیگر تخصیص دهیم، با خطا مواجه
میشویم.
در مقابل، زبانهای دینامیک مانند جاوااسکریپت از سیستم نوع پویا بهرهمند هستند. به این
معنی که یک متغیر میتواند در طول حیات خود مقادیر از نوعهای مختلف را دریافت کند و لذا
هنگام اعلان یک متغیر نیازی به تعیین صریح نوع آن نیست.
مزیت برنامهنویسی به یک زبان استاتیک این است که سختگیریهایی که برای کار با نوعها و
دادهها وجود دارد، از بروز بسیاری از خطاها و باگهای معمول جلوگیری میکند اما در مقابل،
برنامهنویسی به یک زبان دینامیک سادهتر و سریعتر است. به عبارت دیگر، یک زبان استاتیک
به شما اجازه نمیدهد که در دام خیلی از باگها و خطاها گرفتار شوید اما یک زبان دینامیک
اجازه میدهد راحتتر و سریعتر کد بزنید اما در عوض، خودتان باید مراقب باشید که برخی از
اشتباهات را مرتکب نشوید.
جاوااسکریپت یک زبان Multi-paradigm است
جاوااسکریپت زبانی است که از سبکهای برنامهنویسی شیگرا (Object Oriented Programming) و
تابعی (Functional programming) به خوبی پشتیبانی میکند. البته در جاوااسکریپت از شیگرایی
یا OOP به شکلی متفاوت با شیءگرایی کلاسیک که مبتنی بر کلاسهاست، پشتیبانی میشود. در
واقع، در این زبان از مدلی مبتنی بر پروتوتایپ (prototype-based) برای پشتیبانی از OOP
استفاده میشود و این موضوعی است که خوشایند بسیاری از برنامهنویسانی که در کار با
زبانهای C-style به فرم کلاسیک OOP عادت کردهاند، نیست. البته در نسخهی ES6 ساختارهایی
برای تعریف کلاسها معرفی شده و این یکی از مهمترین تغییرات جاوااسکریپت در سالهای اخیر
بوده است.
از طرف دیگر، در جاوااسکریپت حتی توابع نیز نوع خاصی از اشیاء (objects) محسوب میشوند و لذا
یک تابع را میتوان مانند هر شیء دیگری به یک متغیر اختصاص داد. این یکی از مهمترین
موضوعاتی است که پشتیبانی از برنامهنویسی تابعی را در جاوااسکریپت میسر میکند.
جاوااسکریپت؛ بهترین یا بدترین زبان دنیا؟
در مورد جاوااسکریپت و میزان محبوبیت آن بین برنامهنویسان بحثهای زیاد و نظرات متناقضی
وجود دارد. بعضیها جاوااسکریپت را بهترین زبان برنامهنویسی دنیا و بعضی دیگر آن را بدترین
زبان دنیا میدانند. اما علت این همه اختلاف نظر در مورد یک زبان برنامهنویسی چیست؟
محبوبیت یک زبان برنامهنویسی به چه عواملی وابسته است و این محبوبیت چه معنایی دارد؟ آیا
محبوبترین همان بهترین است یا داستان شبیه محبوبیت پراید در کشور ماست؟ آیا اصلاً امکان
تعیین بهترین زبان برنامهنویسی وجود دارد؟
بهترین زبان کدام است؟
در بسیاری از جاها بحث داغی بین مدعیان سردمداری زبانهای برنامهنویسی و فریمورکهای
مختلف در جریان است. لطفاً اینگونه بحثها را جدی نگیرید. متاسفانه خیلی از ما این
پتانسیل را داریم که روی مسائل به مراتب جزئیتر و کماهمیتتر از این نیز تعصب و جهل
به خرج بدهیم و از دایرهی منطق و انصاف خارج شویم. چند روز پیش یکی از دوستان ماجرایی
از پخش دو سریال ایرانی در شبکه نمایش خانگی بر بستر یکی از سرویسهای VOD و درگیری
عجیب و غریب بین طرفداران این دو سریال و کامنتهای مملو از توهین و تهدیدی که خطاب به
همدیگر نوشته بودند، تعریف کرد که به عنوان یک مشت نمونهی خروار، بیانگر یک فرهنگ
عمومی و اخلاق اجتماعی منحط است. جدای از کسانی که از این ماجراها به نوعی منتفع هستند
و تعمداً به آن دامن میزنند و به قول معروف آتشبیار معرکه میشوند، رفتار سایر افراد
نشان میدهد که ما چقدر مستعد این تعصبات بیجا هستیم. طبیعتاً افرادی که روی علایق خود
تا این حد حساسیت و تعصب به خرج میدهند و دنبال تراشیدن لقب بهترین برای آنها و اثبات
این موضوع به دیگران هستند، وقتی به جای علاقه پای تخصصشان در میان باشد از این هم
متعصبانهتر رفتار میکنند. در خیلی از موارد، شخص سعی میکند نقاب منطق و انصاف را نیز
بر چهره بزند اما شما فریب این چیزها را نخورید. حقیقت ماجرا از این قرار است که ما
نمیتوانیم دو زبان برنامهنویسی را کنار هم قرار دهیم و بگوییم کدامیک بهتر است، مگر
اینکه نوع برنامهای را که قصد نوشتن آن را داریم، مشخص کنیم.
همانطور که گفتیم، جاوااسکریپت یک زبان سطح بالا (high-level)، پویا (dynamic) و تفسیر شده
(interpreted) است که از سبکهای برنامهنویسی شیگرا (object oriented) و تابعی
(functional) به خوبی پشتیبانی میکند. دینامیک بودن جاوااسکریپت به این معناست که متغیرهای
این زبان فاقد نوع (untyped) هستند و این با انتظاری که شاید برنامهنویسان زبانهای
استاتیکی مانند C و جاوا دارند، مطابقت ندارد.
این که یک نفر عاشق جاوااسکریپت باشد یا از آن متنفر باشد، تا حد زیادی به شیوهی
برنامهنویسی مورد علاقهی او یا تجربیات قبلیاش در برنامهنویسی بستگی دارد. دینامیک بودن
جاوااسکریپت و امکان تغییر نوع متغیرهای آن، از نظر بعضیها انعطاف و از نظر بعضیها شلختگی
محسوب میشود. به هر حال، جاوااسکریپت مانند پایتون و روبی یا هر زبان دینامیک دیگر نسبت به
زبانهای استاتیک مانند C و C++ و جاوا مزایا و معایبی دارد و در این امر هیچ تردیدی نیست
اما کسانی که مشکلشان با جاوااسکریپت جنبهی تاریخی دارد و به گذشتهی این زبان و فلسفهی
ابتدایی تولید آن و ویژگیهای بحثبرانگیز موجود در نسخههای قدیمی این زبان اشاره میکنند،
باید بدانند که جاوااسکریپت در چند سال اخیر تغییرات زیادی را به خود دیده و از یک زبان
اسکریپتنویسی به یک زبان برنامهنویسی چندمنظوره و کامل تبدیل شده و مکانیزم ‘use strict’
را نیز برای رهایی از دست ویژگیهای عجیب و غریبی که در نسخههای ابتدایی این زبان دیده
میشد، ارائه کرده است.
به هر حال، جاوااسکریپت در این چند سال بهبودهای بسیار زیادی را به خود دیده و در حال حاضر
به جایگاهی رسیده که کسب دانش کار با این زبان به یک مهارت کلیدی برای برنامهنویسان وب و
موبایل تبدیل شده است.