المحتوى الرئيسي:
1. تحليل معنى النطاق المعجمي لجافا سكريبت
2. تحليل سلسلة نطاق المتغيرات
3. ماذا يحدث عند ترقية أسماء المتغيرات؟
كنت أشرح مؤخرًا دورات JavaScript على Chuanzhi Podcast. شعر العديد من الأصدقاء أن JavaScript بسيطة جدًا، لكنهم لم يعرفوا كيفية استخدامها، لذلك قمت بإعداد بعض المحتوى لمشاركته معك.
تشرح هذه السلسلة بشكل أساسي الأجزاء المتقدمة من JavaScript، بما في ذلك سلاسل النطاق والإغلاقات وأنماط استدعاء الوظائف والنماذج الأولية والأشياء الموجهة للكائنات. لم يتم تضمين بناء الجملة الأساسي لـ JavaScript هنا. إذا كنت بحاجة إلى معرفة الأساسيات، فيمكن للطلاب الانتقال إلى http : انتقل إلى //net.itcast.cn لتنزيل مقاطع فيديو مجانية للتعلم. حسنًا، دون مزيد من اللغط، دعنا ننتقل مباشرة إلى موضوعنا.
1. حول النطاق على مستوى الكتلة
عند الحديث عن النطاق المتغير لجافا سكريبت، فهو يختلف عن اللغة المشابهة للغة C التي نستخدمها عادةً.
على سبيل المثال الكود التالي في لغة C#:
انسخ رمز الكود كما يلي:
الفراغ الثابت الرئيسي (سلسلة [] الحجج)
{
إذا (صحيح)
{
عدد صحيح = 10؛
}
System.Console.WriteLine(num);
}
إذا تم تجميع هذا الرمز، فلن يتم تمريره لأن "الاسم num غير موجود في السياق الحالي".
يقتصر نطاق المتغيرات على الأقواس المتعرجة ويسمى نطاق مستوى الكتلة.
في النطاق على مستوى الكتلة، تكون جميع المتغيرات ضمن أقواس التعريف، من بداية التعريف إلى نهاية الأقواس المتعرجة.
يمكن استخدامه ضمن النطاق، ولا يمكن الوصول إليه خارج هذا النطاق
انسخ رمز الكود كما يلي:
إذا (صحيح)
{
عدد صحيح = 10؛
System.Console.WriteLine(num);
}
يمكن الوصول إليه هنا لأنه تم تعريف المتغير واستخدامه داخل نفس الأقواس المتعرجة.
لكن الأمر مختلف في JavaScript. لا يوجد مفهوم للنطاق على مستوى الكتلة في JavaScript.
2. النطاق في جافا سكريبت
في جافا سكريبت، الكود التالي:
انسخ رمز الكود كما يلي:
إذا (صحيح) {
فارنوم = 10؛
}
تنبيه (رقم)؛
نتيجة العملية هي نافذة منبثقة 10. فكيف يكون نطاق المتغيرات محدودًا في JavaScript؟
2.1 الوظيفة تحد من النطاق المتغير
في JavaScript، الوظائف فقط هي التي يمكنها تحديد نطاق المتغير. ماذا يعني ذلك؟
وهذا يعني أنه في JavaScript، يمكن الوصول إلى المتغيرات المحددة داخل الوظيفة داخل الوظيفة، ولكن خارج الوظيفة
غير قادر على الوصول إلى الكود التالي:
انسخ رمز الكود كما يلي:
فار فونك = وظيفة () {
فارنوم = 10؛
};
يحاول {
تنبيه (رقم)؛
} قبض (ه) {
تنبيه (ه)؛
}
عند تشغيل هذا الكود، سيتم طرح استثناء ولن يتم تعريف المتغير num. وبعبارة أخرى، لا يمكن تعريف المتغير المحدد في الدالة
يُستخدم خارج الوظيفة، وبالطبع يمكن استخدامه بحرية داخل الوظيفة، حتى قبل التعيين، انظر الكود التالي:
انسخ رمز الكود كما يلي:
فار فونك = وظيفة () {
تنبيه (رقم)؛
فارنوم = 10؛
تنبيه (رقم)؛
};
يحاول {
وظيفة();
} قبض (ه) {
تنبيه (ه)؛
}
بعد تشغيل هذا الرمز، لن يتم طرح أي خطأ، وستظهر النافذة المنبثقة مرتين، على التوالي غير محدد و10 (سأشرح السبب أدناه).
يمكن أن نرى من هنا أنه لا يمكن الوصول إلى المتغيرات إلا داخل الوظيفة. وبالمثل، يمكن أيضًا الوصول إلى الوظائف داخل الوظيفة.
2.2 النطاق الفرعي يصل إلى المجال الأصلي
كما ذكرنا سابقًا، يمكن للوظيفة أن تحد من نطاق المتغير، وبالتالي تصبح الوظيفة في الوظيفة نطاقًا فرعيًا للنطاق
يمكن للكود الموجود الوصول إلى المتغيرات في المجال الأصلي، راجع الكود التالي:
انسخ رمز الكود كما يلي:
فار فونك = وظيفة () {
فارنوم = 10؛
فار sub_func = وظيفة () {
تنبيه (رقم)؛
};
sub_func();
};
وظيفة();
نتيجة تنفيذ هذا الرمز هي 10. يمكنك رؤية الوصول المتغير المذكور أعلاه ولكن عند الوصول إلى المجال الأصلي في المجال الفرعي
الكود مشروط أيضًا مثل الكود التالي:
انسخ رمز الكود كما يلي:
فار فونك = وظيفة () {
فارنوم = 10؛
فار sub_func = وظيفة () {
فارنوم = 20؛
تنبيه (رقم)؛
};
sub_func();
};
وظيفة();
يحتوي هذا الرمز على "var num = 20;" آخر أكثر من ذي قبل. هذا الرمز موجود في النطاق الفرعي، لذا سيتمكن النطاق الفرعي من الوصول إلى المجال الأصلي.
لقد حدث تغيير، والنتيجة المطبوعة بواسطة هذا الرمز هي 20. أي أن الرقم الذي يتم الوصول إليه بواسطة المجال الفرعي في هذا الوقت هو متغير في المجال الفرعي، وليس المجال الأصلي.
يمكن ملاحظة أن هناك قواعد معينة للوصول عند استخدام المتغيرات في JavaScript، يجب استخدام مترجم JavaScript أولاً
ابحث في مجال المستخدم لمعرفة ما إذا كان هناك تعريف للمتغير. إذا كان الأمر كذلك، استخدم هذا المتغير؛ وإذا لم يكن الأمر كذلك، فابحث عن المتغير في المجال الأصلي.
قياسًا على ذلك، حتى يتم العثور على نطاق المستوى الأعلى، سيتم طرح استثناء "لم يتم تعريف المتغير" راجع الكود التالي:
انسخ رمز الكود كما يلي:
(وظيفة() {
فارنوم = 10؛
(وظيفة() {
فارنوم = 20؛
(وظيفة(){
تنبيه (رقم)؛
})()
})();
})();
بعد تنفيذ هذا الرمز، تتم طباعة 20 إذا تمت إزالة "var num = 20;"، فسيتم طباعة 10 بشكل مماثل، إذا تمت إزالة "var num = 20;".
"var num = 10"، فسيحدث خطأ غير محدد.
3. سلسلة النطاق
مع تقسيم نطاقات JavaScript، يمكن ربط نطاقات الوصول إلى JavaScript في بنية شجرة متسلسلة.
بمجرد أن يتم فهم سلسلة نطاق JavaScript بوضوح، ستكون المتغيرات والإغلاقات في JavaScript واضحة جدًا.
تستخدم الطريقة التالية الرسم لرسم سلسلة النطاق.
3.1 قواعد الرسم:
1) سلسلة النطاق عبارة عن مجموعة من الكائنات
2) جميع البرامج النصية هي سلاسل من المستوى 0، ويحتل كل كائن موضعًا واحدًا
3) عندما ترى وظيفة تمتد إلى سلسلة، قم بتوسيعها مستوى تلو الآخر.
4) عند الوصول، انظر أولاً إلى الوظيفة الحالية إذا لم يتم تعريفها، فتحقق من السلسلة.
5) كرر هذا حتى المستوى 0 من السلسلة
3.2 أمثلة
انظر إلى الكود أدناه:
انسخ رمز الكود كما يلي:
فارنوم = 10؛
فار func1 = وظيفة() {
فارنوم = 20؛
فار func2 = وظيفة () {
فارنوم = 30؛
تنبيه (رقم)؛
};
func2();
};
فار func2 = وظيفة () {
فارنوم = 20؛
فار func3 = وظيفة() {
تنبيه (رقم)؛
};
func3();
};
func1();
func2();
دعنا نحلل هذا الكود:
-> أولًا، الكود بأكمله عبارة عن نطاق عالمي ويمكن وضع علامة عليه كسلسلة نطاق من المستوى 0، ثم هناك مصفوفة
var link_0 = [num, func1, func2];// موصوف هنا برمز زائف
-> هنا func1 و func2 كلاهما وظيفتان، لذلك يتم اشتقاق سلسلتي نطاق من المستوى الأول، وهما
var link_1 = { func1: [ num, func2 ] }; // موصوف هنا برمز زائف
var link_1 = { func2: [ num, func3 ] }; // موصوف هنا برمز زائف
-> سلسلة المستوى الأول الأولى مشتقة من سلسلة المستوى الثاني
var link_2 = { func2: [ num ] }; // موصوف هنا برمز زائف
-> سلسلة المستوى الثاني 1 لا تحتوي على متغيرات محددة وهي سلسلة فارغة، ويتم التعبير عنها كـ
var link_2 = { func3: [ ] };
-> من خلال دمج الكود أعلاه، يمكن التعبير عن سلسلة النطاق على النحو التالي:
انسخ رمز الكود كما يلي:
// موصوف هنا برمز زائف
var link = [ // المستوى 0 chain
رقم,
{ func1 : [ // سلسلة المستوى الأول الأول
رقم،
{ func2 : [ // سلسلة المستوى الثاني
رقم
] }
]},
{ func2 : [ // سلسلة المستوى الثاني 1
رقم,
{ وظيفة 3: [] }
]}
];
-> ممثلة كصورة
الشكل: 01_01 نطاق chain.bmp
ملحوظة: استخدم كود js للتعبير عن مخطط السلسلة، وسيكون واضحًا جدًا عند تمييزه.
باستخدام مخطط سلسلة النطاق هذا، يمكنك أن تفهم بوضوح كيفية تنفيذ الوصول إلى المتغيرات:
عندما تحتاج إلى استخدام متغير، ابحث أولاً عن المتغير في السلسلة الحالية، وإذا وجدته، فاستخدمه مباشرة
ابحث لأعلى، إذا لم يتم العثور عليه، فابحث في سلسلة النطاق ذات المستوى الواحد حتى سلسلة النطاق ذات المستوى 0.
إذا كان بإمكانك تحديد مستوى سلسلة النطاق التي ينتمي إليها المتغير بوضوح شديد، فعند تحليل JavaScript
يكون الأمر سهلاً للغاية عندما يتعلق الأمر بالبرمجة واستخدام ميزات JavaScript المتقدمة مثل عمليات الإغلاق (على الأقل بالنسبة لي).
3. ترقية الاسم المتغير وترقية اسم الوظيفة
مع سلاسل النطاق وقواعد الوصول المتغيرة، هناك مشكلة شائكة للغاية، دعونا نلقي نظرة على ما يلي أولاً
كود جافا سكريبت:
انسخ رمز الكود كما يلي:
فارنوم = 10؛
فار فونك = وظيفة () {
تنبيه (رقم)؛
فارنوم = 20؛
تنبيه (رقم)؛
};
وظيفة();
ماذا ستكون نتيجة التنفيذ؟ يمكنك التفكير في الأمر، ولن أكشف عن الإجابة بعد.
دعونا نحلل هذا الرمز أولاً.
توجد سلسلة نطاق من المستوى 0 في هذا الرمز، والتي تحتوي على رقم الأعضاء و func، ضمن func، توجد وظيفة من المستوى 1.
سلسلة المجال، التي تحتوي على رقم العضو، لذلك، عند استدعاء الوظيفة func، سيتم اكتشاف ذلك في النطاق الحالي
تم تعريف المتغير num، لذلك سيتم استخدام هذا المتغير، ومع ذلك، لم يتم تعيين قيمة num في هذا الوقت، لأن الكود
يتم تشغيل الكود من أعلى إلى أسفل، لذلك، الطباعة الأولى غير محددة، والطباعة الثانية هي 20.
هل فهمت الأمر بشكل صحيح؟
ومن الشائع أيضًا في JavaScript تحديد التعليمات البرمجية في الخلف واستخدامها في المقدمة مثل هذا
سؤال في هذا الوقت يبدو الأمر كما لو تم تعريف المتغير في البداية، والنتيجة هي مثل الكود التالي:
انسخ رمز الكود كما يلي:
فارنوم = 10؛
فار فونك = وظيفة () {
var num;// يبدو أنه قد تم تعريفه هنا، ولكن لا توجد مهمة.
تنبيه (رقم)؛
فارنوم = 20؛
تنبيه (رقم)؛
};
وظيفة();
غالبًا ما تسمى هذه الظاهرة بترويج الاسم المتغير، ويوجد أيضًا ترويج لاسم الوظيفة، على سبيل المثال، الكود التالي:
انسخ رمز الكود كما يلي:
فار فونك = وظيفة () {
تنبيه ("استدعاء وظيفة خارجية")؛
};
فار فو = وظيفة () {
وظيفة();
فار فونك = وظيفة () {
تنبيه ("استدعاء الوظيفة الداخلية")؛
};
وظيفة();
};
حسنًا، كيف يبدو هذا الرمز؟ أو يجب أن يكون هناك شيء مختلف، فلن أترك الأمر للقراء للتفكير!
سأعطي الجواب في المقال القادم.
بسبب هذه الاختلافات، أثناء التطوير الفعلي، يوصى بكتابة جميع المتغيرات في البداية.
وهذا يعني أنه يتم تعريف المتغيرات في بداية الوظيفة، على غرار أحكام لغة C، وهذا ينطبق أيضًا على مكتبات js.
ويتم ذلك، مثل jQuery، وما إلى ذلك.
4. ملخص
حسنًا، تشرح هذه المقالة بشكل أساسي ما هو النطاق المعجمي لجافا سكريبت وشرحه.
كيف نحلل سلسلة النطاق وحالة الوصول للمتغيرات، لننتهي بتمرين آخر! ! !
انظر ما هي نتيجة تنفيذ الكود أدناه:
انسخ رمز الكود كما يلي:
إذا (! "أ" في النافذة) {
var a = "تعريف المتغير";
}
تنبيه (أ)؛