نطاق المتغيّر العام والمحلي

في هذه المقالة، ستتعرّف على نطاق وكيفية عمله في JavaScript.

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

يمكن أن يساعدك النطاق في ما يلي:

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

ما المقصود بالنطاق؟

يحدد نطاق المتغير من أين يمكنك استخدام المتغير داخل التعليمة البرمجية.

تحدِّد لغة JavaScript متغيّرات النطاق العام أو المحلي:

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

تناقش الأقسام اللاحقة في هذه المقالة الكتلة والنطاق اللغوي:

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

عند الوصول إلى متغيّر ضمن نطاقه، تعرض لغة JavaScript القيمة المخصّصة لها أو تعرض رسالة خطأ.

للإعلان عن متغيّر:

  • استخدِم الكلمات الرئيسية var أو const أو let للإعلان عن المتغيّرات على المستوى المحلي أو العالمي.
  • استخدِم الكلمة الرئيسية const أو let للإعلان عن متغيّرات نطاق الحظر.

عندما تُعلن عن متغيّر var في دالة، يتيح الإعلان المتغيّر لأقرب دالة تضمين. لا يمكنك استخدام الكلمة الرئيسية var للإعلان عن المتغيّرات مع نطاق الحظر.

أمثلة على النطاق

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

const greeting = 'hello';
console.log(greeting); // 'hello'

في مثال النطاق العام، يتم تحديد قيمة hello للمتغيّر greeting.

يوضح هذا المثال النطاق المحلي لأنه يشير إلى المتغير greeting مع الكلمة الرئيسية let داخل إحدى الدوال. المتغيّر greeting هو متغيّر على النطاق المحلي وغير متاح خارج الدالة.

function greet() {
  let greeting = 'Hello World!';
  console.log(greeting);
}

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

if (true) {
   const greeting = 'hello';
}

console.log(greeting); // ReferenceError: greeting is not defined

لاحِظ أنّه عندما تحاول الدالة console.log إخراج قيمة المتغيّر greeting، يعرض JavaScript رسالة الخطأ ReferenceError بدلاً من رسالة hello المتوقّعة. لماذا؟

يتم عرض خطأ لأنّ المتغيّر greeting له نطاق حظر وأقرب مجموعة تشكّل جزءًا من العبارة الشرطية if. لا يمكنك الوصول إلى المتغيّرات let وconst التي تذكرها داخل مجموعة من خارج الحظر. وبالتالي، لا يمكنك الوصول إلا إلى المتغيّر greeting بين قوسَين معقوفَين، والذي يحدّد نطاق الحظر.

يصلح هذا المثال الخطأ لأنّه ينقل طريقة console.log(message) داخل الأقواس المعقوفة. وينقل الرمز المعدَّل طريقة console.log(message) داخل المجموعة.

if (true) {
   const greeting = 'hello';
   console.log(greeting);
}

أنواع النطاقات

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

يمكنك الوصول إلى المتغيرات بنطاق عمومي من أي مكان في البرنامج.

جرِّب استخدام ملف HTML يستورد ملفَّي JavaScript: file-1.js وfile-2.js:

<script src="file-1.js"></script>
<script src="file-2.js"></script>

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

يمكنك الاطّلاع على محتوى ملفَي file-1.js وfile-2.js في مقتطف الرمز هذا. لاحِظ مدى توفّر المتغيّر globalMessage في كلا الملفين.

// file-1.js
function hello() {
    var localMessage = 'Hello!';
}

var globalMessage = 'Hey there!';

// file-2.js
console.log(localMessage); // localMessage is not defined
console.log(globalMessage); // Hey there!

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

النطاق المحلي ونطاق الوظيفة

عند إنشاء متغيّرات في دالة JavaScript باستخدام الكلمات الرئيسية var أو let أو const، تكون المتغيّرات محلية في الدالة، وبالتالي لا يمكنك الوصول إليها إلا من داخل الدالة. يتم إنشاء المتغيرات المحلية عند بدء دالة ويتم حذفها بشكل فعال عند الانتهاء من تنفيذ الدالة.

يعرِّف هذا المثال المتغيّر total في الدالة addNumbers(). يمكنك فقط الوصول إلى المتغيّرات a وb, وtotal ضمن الدالة addNumbers().

function addNumbers(a, b) {
    const total = a + b;
}

addNumbers(3, 4);

يمكنك استخدام الكلمتَين الرئيسيتَين let وconst لتسمية المتغيّرات. عند استخدام الكلمة الرئيسية let، يكون بإمكان JavaScript تعديل المتغيّر. في المقابل، عند استخدام الكلمة الرئيسية const، يظل المتغيّر ثابتًا.

var variable1 = 'Declared with var';
var variable1 = 'Redeclared with var';
variable1; // Redeclared with var

let variable2 = 'Declared with let. Cannot be redeclared.';
variable2 = 'let cannot be redeclared, but can be updated';
variable2; // let cannot be redeclared, but can be updated

const variable3 = 'Declared with const. Cannot be redeclared or updated';
variable3; // Declared with const. Cannot be redeclared or updated

حظر النطاق

يتم استخدام عمليات الحظر لتجميع عبارة واحدة أو مجموعة من العبارات معًا. يمكنك استخدام الكلمتَين الرئيسيتَين const أو let للإعلان عن متغيّر محلي لنطاق الحظر. تجدر الإشارة إلى أنّه لا يمكنك استخدام الكلمة الرئيسية var للإعلان عن المتغيّرات بنطاق الحظر.

على سبيل المثال، في هذه المجموعة، يتم تضمين نطاق المتغيّر name وقيمته "Elizabeth" بين الأقواس المعقوفة. لا تتوفّر المتغيّرات ضمن نطاق الحظر خارج نطاق الحظر.

{
    const name = "Elizabeth";
}

يمكنك استخدام المتغيّرات في نطاق الحظر ضمن جُمل if أو for أو while.

دوِّن حلقتَي for ضمن مقتطف الرمز هذا. تستخدم حلقة for واحدة الكلمة الرئيسية var للإعلان عن متغيّر أداة الإعداد، الذي يزيد من خلال الأرقام 0 و1 و2. تستخدم حلقة for الأخرى الكلمة الرئيسية let للإعلان عن متغيّر أداة الإعداد.

for (var i = 0; i < 2; i++) {
    // ...
}

console.log(i); // 2

for (let j = 0; j < 2; j++) {
    // ...
}

console.log(j); // The j variable isn't defined.

في مثال الرمز السابق، قد تلاحظ أنّ المتغيّر i في أول حلقة for تسرّب خارج حلقة for ولا يزال يحتفظ بالقيمة 2 لأنّ الكلمة الرئيسية var لا تستخدم نطاق الحظر. تم إصلاح المشكلة في حلقة for الثانية التي يكون فيها المتغيّر j الذي تم تعريفه باستخدام الكلمة الرئيسية let على نطاق حظر التكرار الحلقي for ولا تحدث بعد انتهاء التكرار الحلقي for.

إعادة استخدام اسم متغيّر في نطاق مختلف

يمكن للنطاق عزل متغير داخل دالة، حتى عند إعادة استخدام اسم المتغير نفسه في مكان آخر في نطاق مختلف.

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

function listOne() {
    let listItems = 10;
    console.log(listItems); // 10
}

function listTwo() {
   let listItems = 20;
   console.log(listItems); // 20
}

listOne();
listTwo();

يتم تحديد القيم المتوقعة لمتغيّرات listItems في الدالتين listOne() وlistTwo()، وبالتالي لا تتعارض مع بعضها البعض.

حالات الإغلاق والنطاق اللغوي

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

في هذا المثال، يشكِّل الرمز إغلاق مع البيئة المعجمية التي يتم إنشاؤها عند استدعاء الدالة outer()، والتي يتم إغلاقها فوق المتغيّر hello. وبالتالي، يتم استخدام المتغير hello داخل دالة رد الاتصال setTimeout.

function outer() {
    const hello = 'world';

    setTimeout(function () {
        console.log('Within the closure!', hello)
    }, 100);
}

outer();

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

الوحدات

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

// hello.js file
function hello() {
  return 'Hello world!';
}

export { hello };

// app.js file
import { hello } from './hello.js';

console.log(hello()); // Hello world!

العرض التوضيحي لأداة العرض المرئي للنطاق

النطاق مفهوم أساسي يجب أن يفهمه كل مطوّر برامج JavaScript. لفهم نظام النطاق بشكل أفضل، يمكنك محاولة كتابة الرمز البرمجي الخاص بك باستخدام JS Scope Visualizer. يستخدم العرض التوضيحي التلوين في الرمز لمساعدتك في عرض نطاقات JavaScript.

الخاتمة

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

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