الملحق

الوراثة النموذجية

باستثناء null وundefined، يحتوي كل نوع بيانات أساسي على النموذج الأوّلي، وهو برنامج تضمين مقابلة يوفر طرقًا للعمل مع القيم. فعند استدعاء طريقة أو بحث خاصية في دالة أولية، تلفّ لغة JavaScript النقطة الأساسية وراء الكواليس وتستدعي الطريقة أو تجري عملية البحث عن الخاصية على كائن برنامج التضمين بدلاً من ذلك.

على سبيل المثال، ليس للسلسلة الحرفية أي طرق خاصة بها، ولكن يمكنك استدعاء الدالة يتم تطبيق طريقة .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

من النادر جدًا أن تحتاج إلى استخدام هذه الدوال الإنشائية، لأنّ لغة JavaScript مضمَّنة يعني التوريث النموذجي أنها لا تقدم أي فائدة عملية. قيد الإنشاء أن تؤدي البداية باستخدام الدالة الإنشائية إلى نتائج غير متوقعة، بسبب النتيجة هي كائن وليست حرفيًا بسيطًا:

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)

أثناء تحليل نص برمجي، يمكن لمترجمي JavaScript استخدام ميزة تسمى الإدراج التلقائي للفاصلة المنقوطة (ASI) لمحاولة تصحيح حالات الحذف الفاصلة المنقوطة. إذا صادف محلل JavaScript رمزًا مميزًا غير مسموح به، إضافة فاصلة منقوطة قبل هذا الرمز المميز لإصلاح خطأ بناء الجملة المحتمل، طالما ينطبق واحد أو أكثر من الشروط التالية:

  • يتم فصل هذا الرمز المميز عن الرمز السابق بواسطة فاصل أسطر.
  • الرمز المميّز هو }.
  • الرمز المميّز السابق هو )، والفاصلة المنقوطة المدرَجة ستكون النهاية. فاصلة منقوطة في عبارة 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 هي محاولة لتصحيح الأخطاء، وليست نوعًا من المرونة النحوية المنشأة إلى JavaScript. تأكد من استخدام الفواصل المنقوطة عندما يكون ذلك مناسبًا حتى لا تعتمد عليه لإنتاج التعليمات البرمجية الصحيحة.

الوضع المتشدد

لقد تطورت المعايير التي تحكم طريقة كتابة JavaScript إلى ما أبعد من ذلك أي شيء يتم اعتباره أثناء التصميم المبكر للغة. كل تغيير جديد على يجب أن يتجنّب السلوك المتوقَّع في JavaScript التسبب في أخطاء في المواقع الإلكترونية الأقدم.

يعالج الإصدار ES5 بعض المشاكل القديمة الأمد بشأن دلالات JavaScript بدون مما يفسّر عمليات التنفيذ الحالية بفرض "الوضع الصارم"، طريقة لاختيار إلى مجموعة أكثر تقييدًا من قواعد اللغة لنص برمجي كامل أو لدالة فردية. لتفعيل الوضع المتشدد، استخدِم السلسلة الحرفية. "use strict"، متبوعة بفاصلة منقوطة، في السطر الأول من النص أو الدالة:

"use strict";
function myFunction() {
  "use strict";
}

يمنع الوضع المتشدد حدوث بعض الأخطاء "غير الآمنة" إجراءات أو ميزات أو عمليات رمي أخطاء صريحة بدلاً من استخدام الكلمة الرئيسية "silent" (الصامت) الشائعة ، ويمنع استخدام بناء الجملة التي قد تتعارض مع ميزات اللغة المستقبلية. على سبيل المثال، قد تكون قرارات التصميم بشأن النطاق المتغير يزيد من احتمال "تلوث" المطوّرين عن طريق الخطأ النطاق العمومي عند إعلان متغير، بغض النظر عن السياق الذي يتضمنه، عن طريق حذف كلمة رئيسية واحدة (var):

(function() {
  mySloppyGlobal = true;
}());

mySloppyGlobal;
> true

ولا يمكن لبيئات تشغيل JavaScript الحديثة تصحيح هذا السلوك بدون المخاطرة اختراق أي موقع ويب يعتمد عليه، إما عن طريق الخطأ أو عمدًا. بدلاً من ذلك، تمنعها لغة JavaScript الحديثة من خلال السماح للمطوّرين باختيار لعمل جديد، وتمكين الوضع المتشدد افتراضيًا فقط في سياق ميزات لغوية جديدة لن تعطّل عمليات التنفيذ القديمة:

(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

حسب المرجع، حسب القيمة

وأي متغير، بما في ذلك خصائص الكائن، الدوال والعناصر في مصفوفة، ضبط أو خريطة، يمكن أن تحتوي إما على قاعدة أولية أو قيمة مرجعية.

فعندما يتم تعيين قيمة أولية من متغير إلى آخر، تعمل لغة JavaScript نسخة من هذه القيمة ويعيّنها للمتغير.

عند تعيين كائن (مثيلات الفئة والصفائف والدوال) إلى متغير، فبدلاً من إنشاء نسخة جديدة من هذا الكائن، يحتوي المتغير على يشير إلى الموضع المخزن للكائن في الذاكرة. لهذا السبب، فإن تغيير يغير الكائن الذي يشير إليه متغير الكائن المشار إليه، وليس فقط أي قيمة يشتمل عليها هذا المتغير. على سبيل المثال، إذا قمت بإنشاء حساب بمتغير يتضمن مرجع كائن، ثم استخدم المتغير الجديد لإضافة خاصية إلى هذا الكائن، تتم إضافة الخاصية وقيمتها مع الكائن الأصلي:

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

تخصيص الذاكرة

تستخدم لغة JavaScript الإدارة التلقائية للذاكرة، ما يعني أنّ الذاكرة لا تحتاج إلى أن يتم تخصيصها أو توزيعها بشكل صريح أثناء عملية التطوير. بينما تفاصيل حول محركات JavaScript لإدارة الذاكرة أكثر من نطاق هذه الوحدة، فإن فهم كيفية تخصيص الذاكرة يوفر سياقًا للعمل على القيم المرجعية.

يوجد "منطقتان" في الذاكرة: "الحزمة" و"الكومة". متاجر Theack البيانات الثابتة - القيم الأساسية والمراجع للكائنات - لأن يمكن تخصيص مقدار ثابت من المساحة اللازمة لتخزين هذه البيانات قبل يتم تنفيذ النص البرمجي. تخزن كومة الذاكرة عناصر العناصر التي تحتاج إلى مساحة مخصصة ديناميكيًا لأن حجمها يمكن أن يتغير أثناء التنفيذ. يتم إخلاء مساحة من الذاكرة من خلال عملية تسمى "مجموعة البيانات المهملة"، يؤدي إلى إزالة الكائنات التي لا تحتوي على مراجع من الذاكرة.

سلسلة التعليمات الرئيسية

إن لغة JavaScript هي في الأساس لغة تتضمن سلسلة محادثات واحدة بها لغة "مزامنة" نموذج التنفيذ، أي أنّه يمكنه تنفيذ مهمة واحدة فقط في كل مرة. ويُطلق على سياق التنفيذ التسلسلي هذا اسم سلسلة المحادثات الرئيسية.

وتتم مشاركة سلسلة التعليمات الرئيسية من خلال مهام المتصفّح الأخرى، مثل تحليل HTML عرض أجزاء الصفحة وعرضها، وتشغيل الرسوم المتحركة بتنسيق CSS، التعامل مع تفاعلات المستخدم بدءًا من البسيطة (مثل تمييز النص) إلى المعقد (مثل التفاعل مع عناصر النموذج). عثر مورّدو المتصفّح على طُرقًا لتحسين المهام التي تؤديها سلسلة التعليمات الرئيسية، لكنّها أكثر تعقيدًا لا يزال بإمكان النصوص البرمجية استخدام الكثير من موارد سلسلة التعليمات الرئيسية والتأثير بشكل عام أداء الصفحة.

يمكن تنفيذ بعض المهام في السلاسل الخلفية التي تسمى Web Workers، مع بعض القيود:

  • ويمكن أن تعمل سلاسل محادثات العامل على ملفات JavaScript المستقلة فقط.
  • لقد قللت بشدة من إمكانية الوصول إلى نافذة المتصفح وواجهة المستخدم أو لم تعد على الإطلاق.
  • فهي محدودة في كيفية التواصل مع سلسلة التعليمات الرئيسية.

تجعلها هذه القيود مثالية للمهام المركزة والكثيفة الموارد التي في سلسلة التعليمات الرئيسية.

حزمة الاتصال

هيكل البيانات المستخدم لإدارة "سياقات التنفيذ" - التعليمة البرمجية التي التي يتم تنفيذها بشكل نشط — وهي عبارة عن قائمة تسمى حزمة الاتصال (غالبًا ما "الحزمة"). عند تنفيذ النص البرمجي لأول مرة، يتم استخدام مترجم JavaScript ينشئ "سياق تنفيذ عمومي" ويدفعها إلى حزمة الاتصال، العبارات داخل هذا السياق العام التي يتم تنفيذها واحدة تلو الأخرى، من أعلى إلى إلى الأسفل. عندما يصادف المترجم الفوري استدعاء دالة أثناء تنفيذ السياق العالمي، فهو يضع "سياق تنفيذ الدالة" لهذا الاتصال على في أعلى الحزمة، ويوقف سياق التنفيذ العام مؤقتًا، وينفّذ الدالة سياق التنفيذ.

في كل مرة يتم فيها استدعاء دالة، يكون سياق تنفيذ الدالة لهذا الاستدعاء يتم وضعها في أعلى الحزمة، أعلى سياق التنفيذ الحالي مباشرةً. تعمل حزمة الاستدعاءات على "الأول، أولًا، أولًا". أساسًا، مما يعني أن معظم يتم تنفيذ استدعاء الدالة الأخير، وهو الأعلى في الحزمة، ويستمر حتى يتم حلها. عند اكتمال هذه الدالة، يزيلها المترجم الفوري من حزمة الاستدعاءات وسياق التنفيذ الذي يحتوي على استدعاء الدالة يصبح العنصر الأعلى في الحزمة مرة أخرى ويستأنف التنفيذ.

تجمع سياقات التنفيذ هذه أي قيم ضرورية لتنفيذها. هم أيضًا في تحديد المتغيرات والدوال المتاحة ضمن نطاق بناءً على سياقها الأصلي، وتحديد وتعيين قيمة الكلمة الرئيسية this في سياق الدالة.

حلقة الحدث وقائمة انتظار معاودة الاتصال

يعني هذا التنفيذ التسلسلي أنّ المهام غير المتزامنة التي تتضمّن معاودة الاتصال مثل استرجاع البيانات من الخادم والاستجابة لتفاعل المستخدم، أو انتظار الموقّتات التي تم ضبطها باستخدام setTimeout أو setInterval، سيؤدي إلى حظر سلسلة التعليمات الرئيسية إلى أن تكتمل هذه المهمة، أو تقاطع سلسلة التعليمات سياق التنفيذ الحالي في لحظة تنفيذ دالة الاستدعاء تتم إضافته إلى المكدس. لمعالجة هذه المشكلة، يدير JavaScript المهام غير المتزامنة باستخدام "نموذج تزامن" قائم على الحدث من "حلقة الحدث" و "قائمة انتظار معاودة الاتصال" (يُشار إليها أحيانًا باسم "قائمة انتظار الرسائل").

عندما يتم تنفيذ مهمة غير متزامنة في سلسلة التعليمات الرئيسية، يستخدم طلب الاستدعاء في وضع سياق تنفيذ الدالة في قائمة انتظار معاودة الاتصال، وليس أعلى حزمة الاتصال. حلقة الحدث هي نمط يسمى أحيانًا المفاعل، الذي يعمل باستمرار يحدد حالة حزمة الاتصال وقائمة انتظار معاودة الاتصال. إذا كانت هناك مهام في تحدد قائمة انتظار معاودة الاتصال وتكرار الحدث أن حزمة الاستدعاءات فارغة، يتم نقل المهام من قائمة انتظار معاودة الاتصال إلى الحزمة واحدة تلو الأخرى وتنفيذه.