المتغيرات

المتغيرات هي هيكل بيانات تعيّن اسمًا تمثيليًا لقيمة. يمكن أن تحتوي على بيانات من أي نوع.

ويُسمى اسم المتغيّر identifier. يجب أن يتّبع المعرّف الصالح. القواعد التالية:

  • يمكن أن تحتوي المعرّفات على أحرف يونيكود وعلامات الدولار ($) وشرطة سفلية. الأحرف (_) والأرقام (0-9) وحتى بعض أحرف Unicode.
  • لا يمكن أن تحتوي المعرّفات على مسافة بيضاء، لأن المحلل يستخدم مسافة بيضاء عناصر الإدخال المنفصلة. على سبيل المثال، إذا حاولت استدعاء متغير my Variable بدلاً من myVariable، يرى المحلل اللغوي معرّفين، my وVariable، وتعرض خطأ في البنية ("رمز مميّز غير متوقع: ).
  • يجب أن تبدأ المعرّفات بحرف أو شرطة سفلية (_) أو علامة الدولار ($). ولا يمكن أن تبدأ بأرقام، وذلك لمنع الالتباس بين الأرقام المعرفات:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    إذا كانت لغة JavaScript تسمح باستخدام الأرقام في بداية المعرّف، سيسمح ذلك معرفات تتكون من أرقام فقط، مما يتسبب في حدوث تعارض بين الأرقام المستخدمة الأرقام والأرقام المستخدمة كمعرّفات:

    let 10 = 20
    
    10 + 5
    > ?
    
  • "الكلمات المحجوزة" إذا كانت ذات مغزى من الناحية التركيبية، لا يمكن استخدامها كمعرّفات.

  • لا يمكن أن تحتوي المعرّفات على رموز خاصة (! . , / \ + - * =).

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

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

let camelCasedIdentifier = true;

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

class MyClass {

}

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

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

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

تعريف المتغيّر

هناك عدة طرق لجعل JavaScript على دراية بالمعرّف، وهي عملية يسمى "الإعلان" متغير. يتم تعريف متغير باستخدام let أو const أو var كلمة رئيسية.

let myVariable;

استخدِم let أو var للإعلان عن متغيّر يمكن تغييره في أي وقت. هذه تخبر الكلمات الرئيسية مترجم JavaScript بأن سلسلة الأحرف الذي قد يحتوي على قيمة.

عند العمل على قاعدة رموز برمجية حديثة، استخدِم let بدلاً من var. لا يزال var يعمل في المتصفحات الحديثة، ولكنها تتضمن بعض السلوكيات غير البديهية التي تم تحديدها في النُسخ الأقدم من JavaScript، ثم تعذر تغييرها لاحقًا إلى الحفاظ على التوافق مع الأنظمة القديمة. تمت إضافة let في ES6 لحلّ بعض المشاكل بتصميم var.

يتم تهيئة المتغير المُعلَن عنه من خلال تعيين قيمة للمتغير. يمكنك استخدام علامة يساوي واحدة (=) لتعيين قيمة لمتغير أو إعادة تعيينها. يمكنك إجراء ما يلي: هذا كجزء من البيان نفسه الذي يذكر أنه:

let myVariable = 5;

myVariable + myVariable
> 10

يمكنك أيضًا التعريف عن متغيّر باستخدام let (أو var) بدون إعداده. في الحال. إذا فعلت ذلك، فستكون القيمة الأولية للمتغير undefined حتى يعينه التعليمة البرمجية قيمة.

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

يختلف المتغيّر الذي يتضمّن قيمة undefined عن متغيّر غير محدَّد. الذي لم يتم الإعلان عن معرّفه بعد. الإشارة إلى متغير لم المعلن عنها إلى خطأ.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

إن الارتباط بين المعرف بإحدى القيم يسمى عمومًا "ربط". يُطلق على البنية التي تتّبع الكلمات الرئيسية let أو var أو const اسم و"قائمة الربط" وتسمح باستخدام تعريفات متغيّرات متعددة مفصولة بفواصل (تنتهي بالفاصلة المنقوطة المتوقعة). يؤدي هذا إلى إنشاء مقتطفات الرمز التالية متطابقة وظيفيًا:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

لا تستخدم إعادة تحديد قيمة متغيّر let (أو var)، لأنّ JavaScript بالفعل وجود المتغير وهو:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

يمكنك إعادة تحديد قيم جديدة للمتغيّرات استنادًا إلى قيمها الحالية:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

إذا حاولت إعادة تعريف متغيّر باستخدام let في بيئة إنتاج، سيظهر لك خطأ في البنية:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

المتصفحات أدوات المطوّرين الأكثر تساهلاً في إعادة تعريف letclass)، لذا قد لا سيظهر لك الخطأ نفسه في وحدة تحكم المطوّرين.

للحفاظ على توافق المتصفِّح القديم، يسمح var بإعادة التعريف غير الضرورية. بدون خطأ في أي سياق:

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

استخدِم الكلمة الرئيسية const للإعلان عن الثابت، وهو نوع من المتغيّرات التي يجب على الفور، ومن ثم لا يمكن تغييرها. معرّفات الثوابت اتّباع جميع القواعد نفسها المستخدَمة في المتغيّرات التي تم تعريفها باستخدام letvar):

const myConstant = true;

myConstant
> true

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

const myConstant;
Uncaught SyntaxError: missing = in const declaration

يمكن أن تؤدي محاولة تغيير قيمة متغير مُعلَن عنه باستخدام const بالطريقة المُعلَنة يؤدي تغيير قيمة المتغير المُعلَن عنه مع let (أو var) إلى نوع خطأ:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

ومع ذلك، عندما يرتبط العدد الثابت بكائن، فإنّ خصائص ذلك يمكن تغيير كائنه.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

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

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

عندما لا تتوقع إعادة تعيين متغير، فمن أفضل الممارسات أن تجعله ثابت. إنّ استخدام "const" يخبر فريق التطوير أو المشرفين المستقبليين مشروعك عدم تغيير تلك القيمة، لتجنب كسر الافتراضات التي قد تؤدي إلى عن كيفية استخدامه - على سبيل المثال، سيتم تحويل المتغير في النهاية قياسها مقابل نوع بيانات متوقع.

نطاق المتغيّر

نطاق المتغير هو ذلك الجزء من البرنامج النصي حيث يتوفر هذا المتغير. خارج نطاق المتغير، لن يتم تعريفه - وليس كمعرف يحتوي على قيمة undefined، ولكن كما لو لم يتم الإعلان عنها.

اعتمادًا على الكلمة الرئيسية التي تستخدمها لتعريف أحد المتغيرات والسياق الذي ويمكنك تعريفه، ويمكنك تحديد نطاق المتغيرات لحظر العبارات (حظر النطاق)، دوال فردية (نطاق الدالة)، أو تطبيق JavaScript بالكامل (النطاق العام).

حظر النطاق

أي متغيّر تعلن عنه باستخدام let أو const يتم تحديده إلى أقرب موضع له. تحتوي على عبارة حظر مما يعني أنه لا يمكن الوصول إلى المتغير إلا داخل هذه الكتلة. جارٍ محاولة يؤدي الوصول إلى متغير ذو نطاق حظر خارج نطاق الكتلة الذي يتضمنه إلى حدوث نفس خطأ كمحاولة للوصول إلى متغيّر غير موجود:

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

وبالنسبة إلى JavaScript، لا يتوفّر متغيّر ضمن نطاق الحظر. خارج الكتلة التي تحتوي عليها. على سبيل المثال، يمكنك الإعلان عن ثابتة داخل كتلة، ثم الإعلان عن ثابت آخر خارج تلك الكتلة التي تستخدم المعرّف نفسه:

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

على الرغم من أنه لا يمكن تمديد المتغير المُعلَن عنه في كتلته الرئيسية، فإنه يتم متاحة لجميع الوحدات الفرعية:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

يمكن تغيير قيمة المتغيّر المعلَن من داخل مجموعة تابعة:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

يمكن إعداد متغيّر جديد باستخدام let أو const داخل عنصر تابع بدون أخطاء، حتى لو تم استخدام نفس المعرف كمتغير في حظر المحتوى الرئيسي:

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

نطاق الوظيفة

يتم تحديد نطاق المتغيّرات المعلَنة باستخدام var وفقًا لأقرب دالة تحتوي على قيمة المتغيّرات. (أو كتلة إعداد ثابتة داخل فئة).

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

لا يزال هذا هو الحال بعد استدعاء الدالة. على الرغم من أن تهيئة المتغير أثناء تنفيذ الدالة، فلا يزال هذا المتغير غير متاحة خارج نطاق الدالة:

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

النطاق العمومي

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

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

يشير هذا المصطلح إلى أي متغيّر تم الإعلان عنه باستخدام var خارج دالة رئيسية، أو باستخدام let أو const خارج نطاق المجموعة الرئيسية عمومًا:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

إن تعيين قيمة لمتغير دون الإعلان عنه صراحةً (أي من خلال عدم استخدام var أو let أو const لإنشائها) إلى رفع متغير إلى نطاق عمومي، حتى عند التهيئة داخل دالة أو كتلة. متغير التي يتم إنشاؤها باستخدام هذا النمط أحيانًا باسم "عالمي ضمني".

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

الرفع المتغير

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

hoistedVariable
> undefined

var hoistedVariable;

ونظرًا لأنه تتم استضافة تعريف المتغير فقط، وليس الإعداد، المتغيّرات التي لم يتم الإعلان عنها صراحةً باستخدام var أو let أو const لا يتم رفعها:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

كما ذكرنا سابقًا، المتغير المُعلَن عنه ولكنه غير مهيأ تم تعيينه لقيمة undefined. ينطبق هذا السلوك على المتغير المرفوع أيضًا، ولكن فقط للتعريفات باستخدام var.

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

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

يتعامل كل من let وconst مع هذا السلوك من خلال عرض خطأ عند يتم الوصول إلى المتغير قبل إنشائه:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

يختلف هذا الخطأ عن "hoistedVariable لم يتم تعريفه" خطأ المستخدم عند محاولة الوصول إلى متغير غير مُعرَّف. لأنّ JavaScript الذي رفع فيه المتغير، فإنه يدرك أنه سيتم إنشاء المتغير داخل للنطاق المحدد. ومع ذلك، فبدلاً من إتاحة هذا المتغير قبل تصريح بقيمة undefined، يعرض المُترجم خطأً. يُقال إنّ المتغيّرات المعلَنة باستخدام let أو const (أو class) موجودة في "منطقة زمنية ثابتة" ("TDZ") من بداية كتلة التضمين حتى في الرمز حيث تم تعريف المتغير.

تجعل المنطقة الثابتة الزمنية سلوك let أكثر سهولة من var المؤلفين. إنّ تصميم "const" مهم أيضًا. لأن الثوابت لا يمكن ثابتًا يرتفع إلى قمة نطاقه ومنحه قيمة ضمنية تعذّر إعداد من undefined باستخدام قيمة مفيدة.

التحقق من فهمك

ما هي أنواع الأحرف التي يمكنك بدء المعرّف بها؟

حرف
شرطة سفلية
رقم

ما هي الطريقة المفضلة للتعريف عن متغير قيمته في أي وقت؟

دع
const
var