سؤال

أجريت اليوم مناقشة مع أحد زملائي حول الوظائف المتداخلة في Javascript:

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}

في هذا المثال، تشير التجارب إلى أنه لا يمكن الوصول إلى b خارج جسم a، مثلما هو الحال مع c.ومع ذلك، d هو - بعد تنفيذ ().ابحث عن التعريف الدقيق لهذا السلوك في معيار ECMAScript v.3 , ، لم أجد الصياغة الدقيقة التي كنت أبحث عنها؛ما لم يذكره القسم 13، ص 71، هو ما هو الكائن الذي يجب أن يرتبط به كائن الوظيفة الذي تم إنشاؤه بواسطة بيان تعريف الوظيفة.هل فاتني شيء؟

هل كانت مفيدة؟

المحلول

هذا هو النطاق الثابت.يتم تحديد نطاق البيانات داخل وظيفة داخل تلك الوظيفة.

ومع ذلك، تتمتع Javascript بسلوك غريب، وهو أنه بدون فار الكلمة الرئيسية، لقد ضمنت أ المتغير العالمي.هذا ما تراه في الاختبار الخاص بك.المتغير "d" الخاص بك متاح لأنه عمومي ضمني، على الرغم من كتابته داخل نص الدالة.

وأيضاً للإجابة على الشق الثاني من سؤالك:توجد الدالة في أي نطاق يتم الإعلان عنه، تمامًا مثل المتغير.

ملاحظة جانبية: ربما لا تريد المتغيرات العامة، وخاصة المتغيرات الضمنية.من المستحسن أن تستخدم دائمًا الكلمة الأساسية var، لمنع الالتباس وللحفاظ على كل شيء نظيفًا.

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

هنا من مواصفات لغة ECMAScript:

10.2 الدخول في سياق التنفيذ

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

عندما يدخل التحكم في سياق التنفيذ ، يتم إنشاء سلسلة النطاق وتهيئتها ، ويتم تنفيذ مثيل متغير ، ويتم تحديد هذه القيمة.

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

هنا من أورايلي جافا سكريبت:الدليل النهائي (الطبعة الخامسة):

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

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

يوصى بشدة بكتابة دوجلاس كروكفورد لتغطية هذه الأنواع من الأسئلة:

جافا سكريبت، الأجزاء الجيدة http://oreilly.com/catalog/covers/9780596517748_cat.gif

جافا سكريبت، الأجزاء الجيدة, ، أيضًا من أورايلي.

نصائح أخرى

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

function a() { ... }

و

var a = function() { ... }

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

function a() {
    d = 'Hello World';
}
alert(window.d); // shows 'Hello World'

ولكن لا يمكنك أن تفعل:

function a() {
    document = 'something';
}

لأنه لا يمكنك الكتابة فوق الكائن window.document.

لجميع الأغراض العملية التي يمكن تصوير أن كل من التعليمات البرمجية الخاصة بك قيد التشغيل في كتلة with(window) العملاق.

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

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

إذن، أنت تستدعي الدالة أ، والدالة أ تعلن عن متغير عام د.

...

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}

ودون أن يسبقه <م> فار ، د عالمي. نفعل ذلك لجعل د الخاص:

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   var d = 'Bound to local object.'
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top