هومن امینی
هومن امینی
خواندن ۱۶ دقیقه·۵ سال پیش

مفاهیم، نکته و ترفندهای جی اس - قسمت ۶ جاوااسکریپت چیست؟

فیلم این مقاله را می توانید در یوتوب مشاهده فرمایید.

لینک کانال بنده در یوتوب، عضویت شما در این کانال باعث امتنان است.

توضیح : بنده در ۵ قسمت های قبلی به مرور متغیرها، آبجکت ها، آرایه ها و فانکشن ها پرداختم اما جهت ارائه مفاهم پیشرفته تر به نظرم مفاهیم پایه ای تر نیز نیاز است، لذا تصمیم گرفتم بر مبنای منابع معتبر و شناخته شده YDKJS یا You Don't Know JS برداشت ها شخصی را طی چند گفتار پیش رو عرض نمایم.

شما هنوز جی اس نمی دانید، من هم به طور کامل نمی دانم، هیچ کدام از ما نمی توانیم این ادعا را داشته باشیم. اما می توانیم شروع کنیم و جی اس را بهتر بدانیم.

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

جی اس زبان گسترده و پیشرفته‌ای با بسیاری از قابلیت ها و ويژگی ها است اما همه جی اس بر پایه سه ستون زیر پایه گذاری شده.

  • محدوده / کلوژر (Scope/Closure)
  • پروتوتایپ / اشیاء (Prototypes/Objects)
  • تایپ /کوارژن (Type/Coercion)

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

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

نام جاوا اسکریپت احتمالا، اشتباه ترین نام گذاری زبان برنامه نویسی است که با باعث سوء تفاهم می گردد.

آیا این زبان وابسته به جاوا است؟ آیا فرم اسکریپت برای جاوا است؟ آیا زبان اسکریپتی است و زبان برنامه نویسی واقعی نیست؟

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

چرا؟ زیرا از آنجاییکه این زبان در ابتدا برای جلب مخاطبین برنامه نویسان جاوا طراحی شده بود و کلمه اسکریپت در آن زمان به علت اینکه اشاره به یک زبان سبک داشته محبوب بوده است.

به عبارت دیگر، نام جاوا اسکریپت یک ابزار بازاریابی بوده است که سعی داشته این زبان را به عنوان یک جایگزین خوشایند برای نوشتن جاوا که سنگین تر و مشهورتر بوده است قرار دهد و شاید نام آن می توانست وب جاوا نام گذاری گردد.

شباهت سطحی بین جاو اسکریپت و جاوا وجود دارد و این شباهت به دلیل این است که هردو آنها از syntax های C پیروی کردند به عنوان مثال در جی اس مانند جاوا از { برای شروع بلاک و } برای پایان بلاک استفاده می نماید و یا از ; برای انتهای statement استفاده می‌شود.

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

نام رسمی که توسط TC39 مشخص شده و توسط نهاد ECMA رسمیت یافته ECMAScript است و در واقع از سال ۲۰۱۶، سال تجدید نظر نیز به نام رسمی اضافه شده است به عنوان مثال ECMAScript 2019 یا به صورت خلاصه EC2019

توجه : TC39 کمیته فنی است که جی اس را مدیریت می کند و این کمیته بین ۵۰ تا ۱۰۰ نفر هستند که از شرکت های هستند که به صورت گسترده در وب سرمایه گذاری نموده اند مانند شرکت های که مرورگر ها را ساخته اند به عنوان مثال Mozila، Google، Apple و شرکت های که دستگاه ها را ساخته اند مانند سامسونگ.

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

"Java is to JavaScript as ham is to hamster." --Jeremy Keith, 2009

مشخصات زبان

کار اصلی کمیته TC39 مدیریت مشخصات (specification) زبان جی اس است و آنها مرتبا جهت رای دادن به تغییرات جلسه برگزار می کنند و تغییرات تایید شده را به سازمان استاندارد ٍECMA ارائه می دهند.

رفتار و syntax جی اس در مشخصات ES تعریف شده است.

از سال ۱۹۹۵ که سال آغاز جی است، ES2019 دهمین specification تجدید نظر شده می باشد و به همین دلیل در URL سایت ECMA با شماره ده است:

https://www.ecma-international.org/ecma-262/10.0/

تمام پیشنهادات کمیته TC39 پنج مرحله که از مرحله صفر(stage 0) تا مرحله چهار (stage 4) است، پیشرفت می کنند.

شما می توانید درباره این مراحل اینجا مطالعه فرمایید.

مرحله ۰ یا stage 0 به این معنی است که اشخاصی در کمیته TC39 بر این عقیده هستند که این ایده ارزش کار کردن دارد و وقتی پروپوزال به مرحله ۴ یا stage 4 رسید برای قرار دادن آن در نسخه مشخصات زبان سال بعد واجد شرایط است و این فرآیند ممکن است از چند ماه تا چند سال طول بکشد.

تمام پروپوزال ها به صورت سرباز در گیت هاب TC39 مدیریت می شوند و هرشخصی می تواند در این پیشنهادات مشارکت داشته باشد اما فقط اعضای کمیته TC39 می توانند به پیشنهادات رای بدهند و لذا نظر کمیته TC39 در مسیر آینده JS وزن زیادی دارد.

تمام سازنده های مرورگرها متعهد شده اند که از این مشخصات پیروی کنند اگرچه ممکن است که پیاده سازی هریک از مشخصات در مرورگرها در زمان های مختلفی انجام شود اما این به این معنی نیست که موردی که در موتور V8 (موتور کروم) پیاده سازی شده با همان مورد که در موتور SpiderMonkey (موتور موزیلا) پیاده سازس شده است، متفاوت و ناسازگار باشد.

وب حکمران همه چیز جی اس است

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

برای مثال کمیته T39 می خواهد متدی به نام contains برای آرایه ها اضافه کند، اما می بیند که این نام با فریم ورک های قدیمی جی اس که هنوز در بعضی از سایت ها استفاده می شود ناسازگار است، بنابراین نام آن را به نام سازگار مانند includes تغییر می دهند.

اما همه جی اس نیست

بعضی از مواردی که در جی می بینیم مانند alert، console.log یا fetch در مشخصات جی اس تعریف نشده است، اما شبیه جی هستند، آنها فانکشن ها و آبجکت متدهای هستند که از سینتکس جی اس پیروی می کنند و رفتارهای پشت آنها بوسیله محیط‌های اجرا جی اس مانند مرورگرها و نودجی اس کنترل می شوند.

دارای چهره های مختلف

واژه پارادایم در زبان های برنامه نویس به طرز نگرش، رویکرد و ساختار آن زبان اشاره دارد.

پارادیام های معروف و معمول شامل رویه ای (Procedural) شئ گرا (Object Orinted) و تابعی (Functional) است.

  • سبک رویه ای کد به صورت بالا به پایین، و مجموعه ای از عملیات که باهم در یک بخش مرتبط بنام رویه یا Procedure جمع شده اند.
  • سبک شئ گرا (OO) با جمع آوری منطق و داده ها در واحدهایی بنام کلاسها، کد را سازماندهی می نمایند.
  • سبک تابعی یا فانکشنال (FP) کد به صورت توابع (توابع pure بر خلاف رویه ها) ساختاردهی می شوند و در آنها تابع ها به عنوان مقدار یا value قابل قبول هستند.

بیشتر زبان ها متمایل به یک پارادایم هستند به عنوان مثال C رویه ای است، جاوا بیشتر بر پایه کلاس است و یا Haskell تابعی است.

اما بعضی زبان ها مثل جاوااسکریپت چند پارادایم را پشتیبانی می کنند شما می توانید در آنها رویه ای، کلاس گرا و یا تابعی کد بنویسید و این کار را لازم نیست برای کل برنامه انجام بدهید و خط خط می توانید با پارادیم های مختلفی انجام دهید.

سازگاری با گذشته و آینده

یکی از اساسی ترین اصولی که جاوااسکریپت آن را رعایت می کند سازگاری با گذاشته است (Backwards Compatibility)

سازگاری با گذشته به این معنی اگر تغییر در حال حاضر در جی اس ایجاد گردد، این باعث نمی گردد که موارد پیشین نامعتبر گردند و کد نوشته شده در سال ۱۹۹۵ هر چند که ابتدایی و محدود باشد، امروز نیز کار می کند و همانطور که اعضای تیم TC39 قول داده اند وب را خراب نمی کنند. "we don't break the web!"

در مقابل سازگاری با گذشته، سازگاری با آینده یا forwards compatibility مطرح است و به این معنی است که اگر مورد جدیدی در برنامه ای باشد، آن برنامه بتواند در موتورهای جی اس های قدیمی اجرا گردد و منجر به شکست برنامه نشود. اما جی اس forwards-compatible نیست.

بر عکس اچ تی ام ال و سی اس اس forwards-compatible هستند اما backwards-compatible نیستند و به این معنی است که HTML و CSS نوشته شده در سال ۱۹۹۵ ممکن است در حال حاضر کار نکند اما اگر شما قابلیت جدید ۲۰۱۹ آنها را در مرورگر ۲۰۱۰ استفاده کنید صفحه شما اجرا می گردد و CSS , HTML که تشخیص داده نشود نادیده گرفته می شود.

پریدن از فاصله ایجاد شده

از آنجاییکه جی اس forwards-compatible نیست به این معنی است که شما همیشه با یک شکاف بین کد می توانید بنویسد و کدی که معتبر برروی موتورهای قدیمی باشد روبرو هستید.

اگر شما یک برنامه با قابلیت های ES2019 برروی موتور ۲۰۱۶ اجرا کنید به احتمال زیاد برنامه شما اجرا نمی گردد و به مشکل برمی خورد و جهت پوشاندن این شکاف برنامه نویسان جی اس می بایست تمهیداتی در نظر داشته باشند.

راه حل ‌syntax های جدید transpiling است و آن به این معنی است با استفاده ابزار یک کد را از یک فرم به فرم دیگر تبدیل نماییم و بر خلاف کامپایل، همچنان کد به صورت متنی است و یا مثلا به زبان ماشین تبدیل نمی گردد.

عبارت Transpiling یا Transpiler این روزها در دنیای مدرن برنامه‌نویسی زیاد استفاده می‌شود. عمل Transpiling در حقیقت تبدیل یک کد از یک زبان به یک زبان هم سطح دیگر است. 

ابزار شناخته شده جهت تبدیل یا Transpiling جی اس های جدید به نسخه های قدیمی Babel است.

برای مثال ممکن است دولوپر کد زیر را نوشته باشد.

if (something) { let x = 3; console.log(x); } else { let x = 4; console.log(x); }

و وقتی این کد جهت مرورگرهای عمومی دیپلوی می گردد توسط Babel به صورت زیر تبدیل می گردد

var x$0, x$1; if (something) { x$0 = 3; console.log(x$0); } else { x$1 = 4; console.log(x$1); }

و همانطور که می بینیم در کد اصلی بوسیله let دوتا محدوده بوسیله if و else ایجاد شده و متغییر x در هر دو محدوده بدون اینکه با هم مداخله تعریف شده اند و در برنامه مشابه که بوسیله babel تولید شده بر آن ها دو متغییر مجزا گرفته شده است و خروجی دو تکه کد یکی است و با این تفاوت که، کد تولید شده توسط Babel قابلیت اجرا در موتورهای قدیمی جی اس را دارد.


پرکردن شکاف ها

موضوع forwards-compatibility به سینتکس های جدید مرتبط نیست، بلکه بیشتر به متد API های که جدیدا اضافه شده مربوط است، رایج ترین راه حل ارایه شده برای متد Apiهای که محیط های قدیمی به صورت بومی آن را تعریف کرده اند. این الگو polyfill نامیده می شود.

این کد را در نظر بگیرید.

// getSomeRecords() returns us a promise for some // data it will fetch var pr = getSomeRecords(); // show the UI spinner while we get the data startSpinner(); pr .then(renderRecords) // render if successful .catch(showError) // show an error if not .finally(hideSpinner) // always hide the spinner

این کد از قابلیت متد finally در پروتوتایپ promise در ES2019 استفاده کرده است و اگر این کد در محیط های قبلی ES2019 اجرا گردد که در آن finally وجود ندارد خطا بوجود خواهد آمد.

و polyfill برای finally در محیط های قبل از ES2019 می تواند به صورت زیر باشد.

if (!Promise.prototype.finally) { Promise.prototype.finally = function f(fn){ return this.then( function t(v){ return Promise.resolve( fn() ) .then(function t(){ return v; }); }, function c(e){ return Promise.resolve( fn() ) .then(function t(){ throw e; }); } ); }; }

ترنسپایلر ها مانند Babel معمولا تشخیص می دهند که چی polyfill های کد شما نیاز دارند و به صورت اتوماتیک برای شما آنها را تولید می کنند. اما گهگاه شما نیاز دارید آن ها به صورت صریح در برنامه تعریف یا include کنید.
از آنجاییکه جی اس توسعه خود را متوقف نمی نماید و این شکاف ناگزیر بوجود خوهد آمد لذا جهت مواجه با شکاف بین کدی که شما استفاده می کنید و کدی که پایدار در محیط های قدیمی تر است، Transpilation و Polyfiliing دو تکنیک موثر می باشد.

تفسیر (Interpretation) چیست؟

یک سئوال بحث بر انگیز برای کد نوشته شده با جی اس این بوده است که آیا جی اس تفسیر می گردد یا کامپایل؟

به نظر می رسد نظر اکثریت این است که جی اس زبان اسکریپتی تفسیر گرا است. اما حقیقت از این پیچیده تر است.

زبان های که کامپایل می گردند معمولا نسخه باینری را جهت اجرا تولید می کنند و به همین دلیل است که خیلی ها می گویند جاو اسکریپت کامپایل نمی گردد.

این ادعاها و انتقادهای نادرست باید کنار گذاشته شود و دلیل واقعی که اهمیت دارد به نحوه برخورد جی اس با خطا ها ربط دارد.

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

اجرای اسکریپتی / تفسیرگرا
اجرای اسکریپتی / تفسیرگرا

در زبان های اسکرپتی و تفسیرگرا خطای خط ۵ برنامه در طول اجرای خط های ۱ تا ۴ تشخیص داده نمی گردد.

این روش را با زبانهایی مقایسه کنید که یک مرحله معمولا parse قبل از اجرا طی می کنند مانند شکل زیر

اجرای کامپایل و parsing
اجرای کامپایل و parsing

و در این مدل خطا خط ۵ در طول مرحله parse تشخیص داده می شود

و جاوا اسکریپت از نوع این نوع زبان است و کد جاوا اسکریپت قبل از اجرا parse می گردد و همانطور که می دانیم خطا ها قبل از اجرا مشخص می گردند به عنوان duplicate بودن پارامترها و اگر عملیات parse انجام نمی شد این خطاها قابل تشخیص قبل از اجرا نبود.

بنابراین جی اس زبان parse شده می باشد، اما آیا کامپایل نیز می گردد؟

جواب به بله نزدیکتر از خیر است و جی اس parse شده به فرم بهینه شده (باینری) جهت اجرا تبدیل می گردد.

جالب اینجاست که جاوا و جاوا اسکریپت در حالی که زبان های بسیار متفاوتی هستند اما از نظر مسئله تفسیر/ کامپایل شباهت زیادی بهم دارند.

جریان کلی جی اس به صورت زیر است

۱- بعد از برنامه ادیتور دولوپر را ترک می کند بوسیله babel ترنسپایل می گردد بوسیله وب پک بسته بندی می گردد و به صورت شکل متفاوت به موتور جی اس تحویل داده می شود.

۲- موتور جی اس کد را parse می کند و یک درخت AST یا Abstract Syntax Tree تولید می کند.

۳- سپس موتور AST را به یک نوع بایت کد یا واسط باینری شده تبدیل می کند که این فایل بوسیله کامپایلر JIT تبدیل و بهینه می گردد.

۴- در آخر ماشینی مجازی جی اس برنامه را اجرا می کند

پارس، کامپایل و اجری جی اس
پارس، کامپایل و اجری جی اس

حال شما بگوید که این فرآیند مانند زبان های تفسیر گرا است یا زبان های کامپایل شده؟

وب اسمبلی (Web Assembly WASM)

یکی از دغدغه هایی که منجر به تکامل جی اس گردیده، عملکرد است، هم چطور جی اس بتواند سریعتر parse و کامپایل شود هم چطور کد کامپایل شده سریعتر اجرا شود.

در سال ۲۰۱۳ مهندسانی از موزیلا فایرفاکس بازی Unreal 3 را از C به جی اس بردند و آن را در مرورگر نشان دادند، قابلیت اجرای این کد در یک موتور مرورگر جی اس با عملکرد ۶۰ فریم در ثانیه بر مجموعه ای از بهینه سازی های که موتور جی اس می توانست به طور خاص انجام دهند پیش بینی شده بود زیرا این بازی از نسخه از جی اس بنام ASM.js استفاده می کرد.

چندین سال پس از اینکه ASM.js اعتبار برنامه هایی که می توانند بوسیله موتوری جی اس پردازش های بشتری انجام دهند را نشان داد گروه دیگر ازمهندسان که در ابتدا موزیلا بودند Web Assembly یا WASM به اختصار را منتشر کردند.

وب اسمبلی از این جهت شبیه ASM.js است که هدف اصلی آن تهیه مسیری برای برنامه های غیر جی اس (C و غیره ) بود که به شکلی بتوانند در موتور جی اس کار کنند اما و نسب به ASM.js برروی کارایی بیشتر بروی موتور جی اس کار کرده است

یکی از منظرهای WASM که در حال ظهور است و به طور مستقیم با وب ارتباط ندارد این است که WASM در حال پیشرفت است که به یک ماشین مجاز (VM) کراس پلتفرم جهت اجرا در انواع پلت فرم ها تبدیل شود.

بنابراین WASM فقط برای وب نیست و WASM جی اس نیست

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

صحبت در باره Strictly

در سال ۲۰۰۹ وقتی ES5 منتشر شد، strict mode به عنوان یک مکانیزم اختیاری برای بهتر شدن جاوا اسکریپت اضافه شد.

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

چرا استریکت مد؟ استریکت مد محدودیت کارهایی که می توانیم انجام بدهیم نیست، بلکه راهنمای برای انجام بهترین کار برای موتور جی است که بتواند کد را به صورت کارآمد و بهینه اجرا نماید و بیشتر کد های جی اس کار تیمی از دولوپرها است بنابراین استفاده از استریکت مد به همکاری برروی کد کمک می کند و از اشتباهات مشکل ساز جلوگیری می‌کند.

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

در هر صورت مد استریکت به صورت یک linter به شما یاد آوری می کند که شانس کارایی و بهترین کیفیت را داشته باشید.

بسیاری این سؤال را می پرسند چرا جی اس استریکت مد را به صورت پیش فرض قرار نداده است؟ و جواب این در بالا توضیح داده و این به خاطر سازگاری با گذشته یا backwards compatibility است

در حال حاضر بیشتر کدهای جی اس در حالت تولید transpile می شوند و در هنگام آن به مد استریکت پایبند می شوند.

و در حال حاضر بیشتر کدها با فرمت ماژول ES6 نوشته می شود و ماژول ES6 به صورت پیش فرض استریکت مد است، بنابراین کلیه کدهای موجود در چنین فایل‌هایی بطور خودکار در حال استریکت مد قرار می گیرند.

تعریف شده ها

جی اس استاندارد ECMAScript (نسخه ES2019 در حال حاضر) که توسط کمیته TC39 هدایت می گردد و توسط ECMA میزبانی می گردد را پیاده سازی می کند.

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

خوب با زبان ما جی اس تعریف شده است بیایید حال با فهم و حواشی آن آشنا شویم.








You Don't Know JSydkjsجاوا اسکریپتجی اسری اکت
برای یادداشت اینجا می نویسم اگر بدرد کسی هم خورد تو روحم گل باز میشه - مهندس نرم افزار - توسعه دهنده وب در فناپ
شاید از این پست‌ها خوشتان بیاید