16

المتغيرات في جافاسكربت بعد ES6

السلام عليكم

سنتطرق في هذا الموضوع إلى طرق تعريف المتغيرات في جافاسكربت بعد الإصدار الجديد ES6

https://en.wikipedia.org/wi...

الموضوع سيكون مختصرا وليس مفصلا

1- دون استخدام كلمة مفتاحية

مثال

x = 2;

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

console.log(x);  //2

المتغير بهذا الشكل يسمى متغير عام (Global variable) بمعنى انك تستطيع الوصول إليه من أي مكان في الكود الخاص بك ولو من داخل function أو حتى في ملف آخر في نفس الصفحة فلو افترضنا أن لديك ملف

one.js

ومحتواه

x = 2;

وملف اخر

two.js

ومحتواه

alert(x); //2

ثم قمت باستدعائهم في نفس الصفحة .. فسيتم عرض قيمة المتغير x بشكل طبيعي في الصفحة .. مع أنه تم تعريفها في ملف واستدعاءها في ملف اخر

وسبب ذلك هو أي متغير عام تقوم بتعريفه .. يتم اسناده بشكل تلقائي إلى الكائن العام window

بمعنى أنه عند تعريفك للمتغير بهذه الطريقة

x = 2;    

تستطيع استدعاؤه بهذه الطريقة أيضا

window.x

ويمكن التحقق عبر تجربة الكود التالي

console.log(window.x) // 2

وهذا ما يفسر ارتباط الملفات بعضها ببعض في نفس الصفحة

مما سبق نستطيع القول أنه:

1) يمكننا تعريف المتغير العام في جافاسكربت بطريقتين

الأولى عن طريق كتابة اسم المتغير واسناد القيمة المرادة له دون استخدام أي كلمة مفتاحية مثل

name = "My Name";

الثانية عبر اسناد اسم المتغير الى الكائن العام window .. مثل

window.name = "My Name";

2) أيضا يمكننا استدعاء المتغير العام بطريقتين

الأولى عن طريقة كتابة اسم المتغير مباشرة مثل

console.log(name); // "My Name"

الطريقة الثانية عبر اسناد اسم المتغير إلى الكائن العام window .. مثل

console.log(window.name); //"My Name"

2- باستخدام كلمة var

مثال

var time = "Now";
console.log(time); //Now

لو قمت باختبارها في ال console سترى النتيجة Now وهذا طبيعي لكن الغريب هو انك اذا قمت باختبارها عن طريق اسناد اسم المتغير إلى الكائن window مثل

console.log(window.time) //Now

وهي نفس النتيجة السابقة .. فهل هذا يعني أن تعريف المتغير باستخدام var يجعله أيضا متغير عام .. إذا ما الفرق بين استخدام كلمة var قبل اسم المتغير او عدم استخدامها

المتغير time في الحالة السابقة هو متغير عام أيضا لكن الفرق يظهر عند استخدامها داخل نطاق (scope) دالة (function) .. مثال

var time = "Now";
function myFun(){
    alert(time)
}

ما سبق مثال تأكيد على أن المتغير time هو متغير عام يمكن الوصول إليه حتى من داخل function او في اي مكان داخل الصفحة

المثال التالي سيوضح الفرق بين استخدام كلمة var داخل وخارج الدالة

var a = "I\'m A";
function myFun(){
    var b = "I\'m B";
}
myFun(); 
alert(a); //I'm A
alert(b); // Error

في المثال السابق .. المتغير a هو متغير عام يمكن الوصول إليه في أي مكان .. لكن المتغير b هو متغير خاص .. أي مقتصر على النطاق الذي تم تعريفه به .. في هذه الحالة هو الدالة myFun فلا يمكن استخدامه خارجها وهذا السبب الذي يجعل ال alert الثانية لا تعمل وتظهر خطأ في ال console

ومما سبق يمكننا القوم .. أن استخدام كلمة var في النطاق العام .. ﻻ يفرق عن عدم استخدامها بمعنى أن الطرق الثالثة التالية متساوية طالما انها ليست داخل نطاق محدد انما هي بشكل عام

x = 1;
var x = 1;
window.x = 1;

3- باستخدام كلمة let

مثال

if(true){
    let color =  "Green";
    console.log(color); // Green
}

انتبه انه تم استخدام if في المثال السابق وهي ﻻ تعطي تأثير كبير والسبب ببساطة ﻷن let في تعريف المتغيرات الخاصة داخل قطاع معين (block) مثل دالة أو حلقة تكرارية أو جملة شرطية كما في المثال السابق

مثال اخر للتوضيح

function testLet(){
    let x = "Hello, World!";
    console.log(x);
  }
testLet(); // Hello, World!
console.log(x); // Error

في المثال السابق المتغير x لا يمكن استخدامه الا داخل الدالة testLet

حسنا السؤال هنا ما الفرق بين let و var إذا تم استخدامها داخل نفس الدالة

مثال

function testVarLet(){
    var v = "var variable";
    let l = "let variable";
}

في المثال السابق لا فرق بينهما فكلا المتغيرين يمكن الوصل له من داخل الدالة فقط

مثال اخر يوضح الفرق بين الاثنين

function testVarLet(){
   // var
   for( var i = 0; i < 3; i++ ){
        console.log("i = " + i) 
   }
   console.log(i) // 3
  }

 // let
  for(let x = 0; x < 3; x++){
       console.log("x =" + x)
   }
   console.log(x) //Error
}

في هذا المثال يظهر الفرق بينهما

بالنسبة ل var عند تعريف متغير باستخدامها فيمكن استخدام هذا المتغير في اي مكان داخل هذه الدالة حتى ولو كان تعريف المتغير تم داخل قطاع داخلي للدالة مثل حلقة التكرار في المثال السابق .. قيمة i تم استدعاءها خارج حلقة التكرار ومع ذلك قيمتها ظهرت 3 بينما let لو كان استخدامها داخل قطاع داخلي للدالة فلايمكن استخدامها خارج هذا القطاع الفرعي وهو حلقة التكرار في المثال السابق وذلك سبب ظهور الخطأ عند محاولة الوصول له خارج حلقة التكرار التي تم تعريفه بها 

على الرغم من ان الاستدعاء تم داخل نفس الدالة التي تم تعريفه بها

4- باستخدام كلمة const

يمكننا اختصار الوقت هنا .. بجملة واحدة

أن const تساوي let لكن الفرق أن const لايمكن تغيير قيمة المتغير (Overwrite) بينما let تستطيع تغيير قيمة المتغير مثال

if(true){
   let x = 1;
   x = 2;
   console.log(x); //2
}

في المثال السابق سيتم تعديل قيمة x من 1 إلى 2 دون مشاكل .. الان حاول ان تسبدل let ب const في نفس المثال

if(true){
    const x = 1;
    x = 2; //Error
    console.log(x);
 }

سيحصل خطأ ﻷنك حاولت تعديل قيمة ثابت .. حيث ما يتم تعريفه ب const يعتبر ثابت غير قابل للتغيير

بعض الملاحظات على المتغيرات

تحديث قيمة المتغير

عند كتابة الأمر التالي في جافاسكربت فهو يحمل أحد احتمالين

 x = 3;

الاحتمال الأول:

وهو تعريف المتغير x وفي هذه الحالة فهو متغير عام .. يمكن الوصول إليه من أي مكان داخل الصفحة

الاحتمال الثاني:

وهو تحديث قيمة متغير سابق بنفس الاسم فلو كان لدينا متغير x قيمته 1 فسيتم تحديث قيمته بعد تنفيذ هذا الأمر

فما يحدث هو البحث عن متغير بنفس الاسم .. فان وجد تم تحديثه واﻻ فيتم الاعلان عن متغير جديد ويلاحظ أن هذه الطريقة ﻻيمكن استخدامها في تعريف المتغيرات عند تفعيل الوضع الصارم (strict mode)

الاعلان عن متغير عن طريق استخدام this

يمكنك تعريف متغير عن طريق استخدام this

مثال:

this.myVar = 9;
console.log(myVar); // 9

ويلاحظ ان هذه الطريقة لن تنفع إلا إذا كنت بالمتغير العام window حيث يشير this في هذه الحالة له والا فلن ينجح الامر

شكرا @يوسف-سيد على التنبيه


المصادر:

[1]

https://leanpub.com/underst...

[2]

[3]

https://developer.mozilla.o...

يوسف سيد أضف ردا

شكرًا لمجهودك لدي بعض الملاحظات:

1- دون استخدام كلمة مفتاحية

ذا لا ينصح به أبدًا أبدًا في ES6 أو ES5 أو غيرهما لأنّه أولًا تصميم سيء كان الهدف من هذا الطريقة هو التعريف العام للمتغيرات، ثانيًا هي لا تعمل بداخل الوضع الصارم Strict Mode وهو بالمناسبة ليس خاصًا بـES6، لذا:

window.Glob = 2;

أو في NodeJS:

global.Glob =2;

وغيرها من سياقات JavaScript ..، أفضل بكثير، مع أنّ المتغيرات العمومية حقًا سيئة، وهو تصميم عابواْ عليه جافا سكربت، يكفي أن تبحث عن Why Does JavaScript Suck! وستجدهم يتحدثون عن هذا.

لو قمت باختبارها في ال console سترى النتيجة Now وهذا طبيعي لكن الغريب هو انك اذا قمت باختبارها عن طريق اسناد اسم المتغير إلى الكائن window مثل

وهي نفس النتيجة السابقة .. فهل هذا يعني أن تعريف المتغير باستخدام var يجعله أيضا متغير عام .. إذا ما الفرق بين استخدام كلمة var قبل اسم المتغير او عدم استخدامها

ليس تمامًا، المتغير المُعرف بالمفتاح var يكون عامًا في الـScope الخاص به لذا من المنطقي عند تعريفك إياه بداخل سياق JS العام سيكون عامًا! لكن إذا عرفته بداخل دالة أخرى مثلًا لن يكون عامًا.

ومما سبق يمكننا القوم .. أن استخدام كلمة var في النطاق العام .. ﻻ يفرق عن عدم استخدامها بمعنى أن الطرق الثالثة التالية متساوية طالما انها ليست داخل نطاق محدد انما هي بشكل عام

x = 1;

var x = 1;

window.x = 1;

ليس تمامًا أيضًا في المثال الأول أنت تعرف مُتغير بالطريقة العامة القديمة، الثانية أنت تعرف مُتغير عام في الـScope، الثالثة أن تعرف تابع للكائن window الذي ليس بالضرورة أن يكون عامًا.

يمكنك تعريف متغير عن طريق استخدام this

مثال:

this.myVar = 9;

console.log(myVar); // 9

أنت لا تعلن إلا عن تابع لـthis الذي ليست بالضرورة أن تكون الكائن العام على إختلاف السياق من الممكن أن تكون رقمًا، قيمة منطقية، Null، undefined، NaN...

شكرا جدا على ردك ..

ثانيًا هي لا تعمل بداخل الوضع الصارم Strict Mode

اشرت الى ذلك في نهاية الموضوع

ويلاحظ أن هذه الطريقة ﻻيمكن استخدامها في تعريف المتغيرات عند تفعيل الوضع الصارم (strict mode)


وهو بالمناسبة ليس خاصًا بـES6، لذا:

اعلم ذلك لكن الطرق المذكورة هي عامة وليسة مقتصرة على ES6 والدليل على ذلك هو كلمة var لكن سبب العنوان هو الإشارة إلى تضمين let و const داخل الشرح


ليس تمامًا، المتغير المُعرف بالمفتاح var يكون عامًا في الـScope الخاص به لذا من المنطقي عند تعريفك إياه بداخل سياق JS العام سيكون عامًا! لكن إذا عرفته بداخل دالة أخرى مثلًا لن يكون عامًا.

نعم تعمدت ذلك لاجعل القاريء يطرح السؤال .. ثم قمت بالايضاح في الاسطر التي تليها مباشرة .. يمكنك المراجعة بداية من

المثال التالي سيوضح الفرق بين استخدام كلمة var داخل وخارج الدالة .. الخ


ليس تمامًا أيضًا في المثال الأول أنت تعرف مُتغير بالطريقة العامة القديمة، الثانية أنت تعرف مُتغير عام في الـScope، الثالثة أن تعرف تابع للكائن window الذي ليس بالضرورة أن يكون عامًا.

ذكرت شرط لتساوي هذه الطرق بعد ذكر هذه الطرق مباشرة

ومما سبق يمكننا القوم .. أن استخدام كلمة var في النطاق العام .. ﻻ يفرق عن عدم استخدامها بمعنى أن الطرق الثالثة التالية متساوية طالما انها ليست داخل نطاق محدد انما هي بشكل عام


أنت لا تعلن إلا عن تابع لـthis الذي ليست بالضرورة أن تكون الكائن العام على إختلاف السياق من الممكن أن تكون رقمًا، قيمة منطقية، Null، undefined، NaN...

كلامك صحيح .. ربما كان علي التنبيه

قمت بتعديل الموضوع وتحديث هذه النقطة


أشكرك جدا على التنبيهات :")