وراثت نمونه اولیه
به استثنای null
و undefined
، هر نوع داده اولیه دارای یک نمونه اولیه است، یک شیء بسته بندی متناظر که روش هایی را برای کار با مقادیر ارائه می دهد. هنگامی که یک متد یا جستجوی ویژگی در یک اولیه فراخوانی می شود، جاوا اسکریپت اولیه را در پشت صحنه می پیچد و متد را فراخوانی می کند یا به جای آن جستجوی ویژگی را روی شی wrapper انجام می دهد.
به عنوان مثال، یک string literal هیچ متد مخصوص به خود ندارد، اما میتوانید متد .toUpperCase()
را به لطف بسته بندی شی String
مربوطه روی آن فراخوانی کنید:
"this is a string literal".toUpperCase();
> THIS IS A STRING LITERAL
این وراثت نمونه اولیه نامیده می شود - به ارث بردن خواص و روش ها از سازنده متناظر یک مقدار.
Number.prototype
> Number { 0 }
> constructor: function Number()
> toExponential: function toExponential()
> toFixed: function toFixed()
> toLocaleString: function toLocaleString()
> toPrecision: function toPrecision()
> toString: function toString()
> valueOf: function valueOf()
> <prototype>: Object { … }
شما می توانید با استفاده از این سازنده ها، به جای اینکه فقط آنها را با مقدارشان تعریف کنید، اولیه ها را ایجاد کنید. به عنوان مثال، با استفاده از سازنده String
یک شی رشته ایجاد می کند، نه یک رشته واقعی: یک شی که نه تنها حاوی مقدار رشته ما است، بلکه تمام ویژگی ها و روش های به ارث برده شده سازنده را شامل می شود.
const myString = new String( "I'm a string." );
myString;
> String { "I'm a string." }
typeof myString;
> "object"
myString.valueOf();
> "I'm a string."
در بیشتر موارد، اشیاء به دست آمده مانند مقادیری رفتار می کنند که ما برای تعریف آنها استفاده کرده ایم. به عنوان مثال، حتی اگر تعریف یک مقدار عدد با استفاده از سازنده new Number
منجر به یک شی حاوی تمام روشها و ویژگیهای نمونه اولیه Number
میشود، میتوانید از عملگرهای ریاضی روی آن اشیا استفاده کنید، همانطور که در اعداد واقعی استفاده میکنید:
const numberOne = new Number(1);
const numberTwo = new Number(2);
numberOne;
> Number { 1 }
typeof numberOne;
> "object"
numberTwo;
> Number { 2 }
typeof numberTwo;
> "object"
numberOne + numberTwo;
> 3
شما به ندرت نیاز به استفاده از این سازنده ها خواهید داشت، زیرا وراثت نمونه داخلی جاوا اسکریپت به این معنی است که آنها هیچ مزیت عملی ندارند. ایجاد اولیهها با استفاده از سازندهها نیز میتواند منجر به نتایج غیرمنتظره شود، زیرا نتیجه یک شی است، نه یک کلمه ساده:
let stringLiteral = "String literal."
typeof stringLiteral;
> "string"
let stringObject = new String( "String object." );
stringObject
> "object"
این می تواند استفاده از عملگرهای مقایسه دقیق را پیچیده کند:
const myStringLiteral = "My string";
const myStringObject = new String( "My string" );
myStringLiteral === "My string";
> true
myStringObject === "My string";
> false
درج خودکار نقطه ویرگول (ASI)
در حین تجزیه یک اسکریپت، مفسران جاوا اسکریپت می توانند از ویژگی به نام درج خودکار نقطه ویرگول (ASI) برای تصحیح نمونه هایی از نقطه ویرگول های حذف شده استفاده کنند. اگر تجزیه کننده جاوا اسکریپت با نشانه ای مواجه شود که مجاز نیست، سعی می کند قبل از آن نشانه، یک نقطه ویرگول اضافه کند تا خطای نحوی احتمالی را برطرف کند، تا زمانی که یک یا چند شرط زیر درست باشد:
- آن توکن با یک شکست خط از توکن قبلی جدا می شود.
- آن نشانه
}
است. - نشانه قبلی
)
است و نقطه ویرگول درج شده نقطه ویرگول پایانی دستورdo
…while
خواهد بود.
برای اطلاعات بیشتر، به قوانین ASI مراجعه کنید.
به عنوان مثال، حذف نقطه ویرگول بعد از عبارات زیر به دلیل ASI باعث خطای نحوی نمی شود:
const myVariable = 2
myVariable + 3
> 5
با این حال، ASI نمی تواند چندین عبارت را در یک خط حساب کند. اگر بیش از یک عبارت را در یک خط می نویسید، مطمئن شوید که آنها را با نقطه ویرگول از هم جدا کنید:
const myVariable = 2 myVariable + 3
> Uncaught SyntaxError: unexpected token: identifier
const myVariable = 2; myVariable + 3;
> 5
ASI تلاشی برای تصحیح خطا است، نه نوعی انعطافپذیری نحوی که در جاوا اسکریپت تعبیه شده است. اطمینان حاصل کنید که در صورت لزوم از نقطه ویرگول استفاده کنید تا برای تولید کد صحیح به آن تکیه نکنید.
حالت سختگیرانه
استانداردهای حاکم بر نحوه نگارش جاوا اسکریپت بسیار فراتر از هر چیزی که در طراحی اولیه این زبان در نظر گرفته شده است، تکامل یافته است. هر تغییر جدیدی در رفتار مورد انتظار جاوا اسکریپت باید از ایجاد خطا در وب سایت های قدیمی جلوگیری کند.
ES5 با معرفی «حالت سختگیرانه»، راهی برای انتخاب یک مجموعه محدودتر از قوانین زبان برای کل اسکریپت یا یک تابع جداگانه، به برخی از مشکلات دیرینه معناشناسی جاوا اسکریپت بدون شکستن پیادهسازیهای موجود میپردازد. برای فعال کردن حالت سخت، از رشته تحت اللفظی "use strict"
و به دنبال آن یک نقطه ویرگول در خط اول یک اسکریپت یا تابع استفاده کنید:
"use strict";
function myFunction() {
"use strict";
}
حالت سختگیرانه از برخی اقدامات «ناامن» یا ویژگیهای منسوخ جلوگیری میکند، خطاهای صریح را به جای خطاهای رایج «بیصدا» پرتاب میکند و استفاده از نحوی را که ممکن است با ویژگیهای زبان آینده برخورد کند، ممنوع میکند. به عنوان مثال، تصمیمات اولیه طراحی در مورد دامنه متغیر باعث میشود توسعهدهندگان به اشتباه دامنه جهانی را هنگام اعلام یک متغیر، بدون توجه به بافت حاوی، با حذف کلمه کلیدی var
، «آلوده» کنند:
(function() {
mySloppyGlobal = true;
}());
mySloppyGlobal;
> true
زمانهای اجرا مدرن جاوا اسکریپت نمیتوانند این رفتار را بدون خطر شکستن وبسایتی که به آن متکی است، اشتباهاً یا عمداً اصلاح کنند. در عوض، جاوا اسکریپت مدرن با اجازه دادن به توسعهدهندگان برای انتخاب حالت سختگیرانه برای کار جدید، و فعال کردن حالت سختگیرانه بهطور پیشفرض تنها در زمینه ویژگیهای زبان جدید که در آن پیادهسازیهای قدیمی شکسته نمیشوند، از آن جلوگیری میکند:
(function() {
"use strict";
mySloppyGlobal = true;
}());
> Uncaught ReferenceError: assignment to undeclared variable mySloppyGlobal
شما باید "use strict"
به عنوان یک رشته به معنای واقعی کلمه بنویسید. الگوی تحت اللفظی ( use strict
) کار نخواهد کرد. شما همچنین باید قبل از هر کد اجرایی در متن مورد نظر خود "use strict"
را وارد کنید. در غیر این صورت، مترجم آن را نادیده می گیرد.
(function() {
"use strict";
let myVariable = "String.";
console.log( myVariable );
sloppyGlobal = true;
}());
> "String."
> Uncaught ReferenceError: assignment to undeclared variable sloppyGlobal
(function() {
let myVariable = "String.";
"use strict";
console.log( myVariable );
sloppyGlobal = true;
}());
> "String." // Because there was code prior to "use strict", this variable still pollutes the global scope
با مرجع، ارزش جانبی
هر متغیری، از جمله ویژگیهای یک شی، پارامترهای تابع ، و عناصر موجود در یک آرایه ، مجموعه یا نقشه ، میتواند حاوی یک مقدار اولیه یا یک مقدار مرجع باشد.
هنگامی که یک مقدار اولیه از یک متغیر به متغیر دیگر اختصاص داده می شود، موتور جاوا اسکریپت یک کپی از آن مقدار ایجاد می کند و آن را به متغیر اختصاص می دهد.
هنگامی که یک شی (نمونه های کلاس، آرایه ها و توابع) را به یک متغیر اختصاص می دهید، به جای ایجاد یک کپی جدید از آن شی، متغیر حاوی ارجاعی به موقعیت ذخیره شده شی در حافظه است. به همین دلیل، تغییر یک شی ارجاع شده توسط یک متغیر، شی مورد ارجاع را تغییر می دهد، نه فقط مقدار موجود در آن متغیر. به عنوان مثال، اگر یک متغیر جدید را با یک متغیر حاوی یک مرجع شی مقداردهی کنید، سپس از متغیر جدید برای اضافه کردن یک ویژگی به آن شی استفاده کنید، ویژگی و مقدار آن به شی اصلی اضافه میشود:
const myObject = {};
const myObjectReference = myObject;
myObjectReference.myProperty = true;
myObject;
> Object { myProperty: true }
این نه تنها برای تغییر اشیاء، بلکه برای انجام مقایسههای دقیق نیز مهم است، زیرا برابری دقیق بین اشیا مستلزم ارجاع هر دو متغیر به یک شیء برای ارزیابی true
است. آنها نمی توانند به اشیاء مختلف ارجاع دهند، حتی اگر آن اشیا از نظر ساختاری یکسان باشند:
const myObject = {};
const myReferencedObject = myObject;
const myNewObject = {};
myObject === myNewObject;
> false
myObject === myReferencedObject;
> true
تخصیص حافظه
جاوا اسکریپت از مدیریت خودکار حافظه استفاده می کند، به این معنی که حافظه نیازی به تخصیص یا تخصیص صریح در طول دوره توسعه ندارد. در حالی که جزئیات رویکردهای موتورهای جاوا اسکریپت برای مدیریت حافظه فراتر از محدوده این ماژول است، درک نحوه تخصیص حافظه زمینه مفیدی را برای کار با مقادیر مرجع فراهم می کند.
دو "منطقه" در حافظه وجود دارد: "پشته" و "هیپ". پشته داده های استاتیک - مقادیر اولیه و ارجاع به اشیاء - را ذخیره می کند، زیرا مقدار ثابتی از فضای مورد نیاز برای ذخیره این داده ها را می توان قبل از اجرای اسکریپت اختصاص داد. هیپ اشیایی را ذخیره می کند که به فضای اختصاص داده شده به صورت پویا نیاز دارند زیرا اندازه آنها می تواند در طول اجرا تغییر کند. حافظه با فرآیندی به نام "جمع آوری زباله" آزاد می شود که اشیایی را که هیچ مرجعی ندارند از حافظه حذف می کند.
موضوع اصلی
جاوا اسکریپت اساساً یک زبان تک رشته ای با یک مدل اجرای "همگام" است، به این معنی که می تواند تنها یک کار را در یک زمان اجرا کند. این زمینه اجرای متوالی، رشته اصلی نامیده می شود.
رشته اصلی توسط سایر وظایف مرورگر، مانند تجزیه HTML، رندر و رندر مجدد بخشهای صفحه، اجرای انیمیشنهای CSS، و مدیریت تعاملات کاربر از ساده (مانند برجسته کردن متن) تا پیچیده (مانند تعامل با فرم) به اشتراک گذاشته میشود. عناصر). فروشندگان مرورگر راههایی برای بهینهسازی وظایف انجامشده توسط رشته اصلی پیدا کردهاند، اما اسکریپتهای پیچیدهتر همچنان میتوانند بیش از حد از منابع رشته اصلی استفاده کنند و بر عملکرد کلی صفحه تأثیر بگذارند.
برخی از کارها را می توان در رشته های پس زمینه به نام Web Workers با برخی محدودیت ها اجرا کرد:
- موضوعات کارگر فقط می توانند روی فایل های جاوا اسکریپت مستقل عمل کنند.
- آنها دسترسی به پنجره مرورگر و UI را به شدت کاهش داده اند یا اصلاً دسترسی ندارند.
- آنها در نحوه برقراری ارتباط با موضوع اصلی محدود هستند.
این محدودیتها آنها را برای کارهای متمرکز و با منابع فشرده که در غیر این صورت ممکن است موضوع اصلی را اشغال کنند، ایدهآل میکند.
پشته تماس
ساختار داده ای که برای مدیریت "زمینه های اجرا" استفاده می شود - کدی که به طور فعال اجرا می شود - لیستی است به نام پشته تماس (اغلب فقط "پشته"). هنگامی که یک اسکریپت برای اولین بار اجرا می شود، مفسر جاوا اسکریپت یک "زمینه اجرای جهانی" ایجاد می کند و آن را به پشته فراخوانی می فرستد، با عباراتی که در داخل آن زمینه جهانی یکی یکی اجرا می شوند، از بالا به پایین. هنگامی که مفسر در حین اجرای متن کلی با یک فراخوانی تابع مواجه می شود، یک "زمینه اجرای تابع" را برای آن فراخوانی به بالای پشته فشار می دهد، زمینه اجرای سراسری را متوقف می کند و زمینه اجرای تابع را اجرا می کند.
هر بار که یک تابع فراخوانی می شود، زمینه اجرای تابع برای آن فراخوانی به بالای پشته، درست بالای زمینه اجرای فعلی فشار داده می شود. پشته فراخوانی بر اساس "اولین ورود، اولین خروج" عمل می کند، به این معنی که آخرین فراخوانی تابع، که بالاترین در پشته است، اجرا می شود و تا زمانی که حل شود ادامه می یابد. هنگامی که آن تابع کامل شد، مفسر آن را از پشته فراخوانی حذف می کند و زمینه اجرایی که شامل آن فراخوانی تابع است، دوباره به بالاترین مورد در پشته تبدیل می شود و اجرا را از سر می گیرد.
این زمینه های اجرایی هر مقدار لازم برای اجرای خود را دریافت می کنند. آنها همچنین متغیرها و توابع موجود در محدوده تابع را بر اساس زمینه اصلی آن ایجاد می کنند و مقدار this
کلمه کلیدی را در بافت تابع تعیین و تنظیم می کنند.
حلقه رویداد و صف پاسخ به تماس
این اجرای متوالی به این معنی است که کارهای ناهمزمان که شامل توابع پاسخ به تماس هستند، مانند واکشی داده ها از سرور، پاسخ به تعامل کاربر، یا انتظار برای تایمرهای تنظیم شده با setTimeout
یا setInterval
، یا رشته اصلی را تا زمانی که آن کار کامل شود مسدود می کند، یا به طور غیرمنتظره ای قطع می شود. زمینه اجرای فعلی لحظه ای که زمینه اجرای تابع برگشت به پشته اضافه می شود. برای رفع این مشکل، جاوا اسکریپت وظایف ناهمزمان را با استفاده از یک "مدل همزمانی" مبتنی بر رویداد که از "حلقه رویداد" و "صف پاسخ به تماس" تشکیل شده است (که گاهی اوقات به عنوان "صف پیام" نامیده می شود) مدیریت می کند.
هنگامی که یک کار ناهمزمان در رشته اصلی اجرا می شود، زمینه اجرای تابع پاسخ به تماس در صف پاسخ به تماس قرار می گیرد، نه در بالای پشته تماس. حلقه رویداد الگویی است که گاهی اوقات راکتور نامیده می شود، که به طور مداوم وضعیت پشته تماس و صف برگشت تماس را نظرسنجی می کند. اگر وظایفی در صف برگشت تماس وجود داشته باشد و حلقه رویداد مشخص کند که پشته تماس خالی است، وظایف از صف پاسخ به تماس یکی یکی به پشته فشار داده می شود تا اجرا شوند.