توجد (أيضًا) طريقة أخرى لإنشاء الدوال. صحيح هي نادرة الاستعمال ولكن لا مفرّ منها في حالات معيّنة.
الصياغة
إليك صياغة إنشاء الدالة:
let func = new Function ([arg1, arg2, ...argN], functionBody);
نصنع الدالة بالوُسطاء arg1...argN
ونمرّر متنها functionBody
.
«هات الشيفرة وقلّل ثرثرتك»… صحيح، هذا أسهل. إليك الدالة وفيها وسيطين اثنين:
let sum = new Function('a', 'b', 'return a + b'); alert( sum(1, 2) ); // 3
وهنا دالة بلا وُسطاء فيها متنها فقط:
let sayHi = new Function('alert("Hello")'); sayHi(); // Hello
الفرق الأساس بين هذه الطريقة والطرائق الأخرى هي أنّا نصنع الدالة هنا (كما لاحظت) من سلسلة نصية حرفيًا، ونمرّرها في وقت تشغيل الشيفرة.
ألزمتنا التصريحات السابقة كلها - ألزمتنا نحن المطوّرين أن نكتب شيفرة الدالة في السكربت.
ولكن صياغة new Function
تسمح لنا بأن نحوّل أيّ سلسلة نصية لتصير دالة. فمثلًا يمكن أن نستلم دالة جديدة من أحد الخواديم وننفّذها:
let str = ... نستلم الشيفرة ديناميكيًا من الخادوم ... let func = new Function(str); func();
لا نستعمل هذه إلا في حالات خاصّة، مثل لو استلمنا الشيفرة من الخادوم أو صنعنا الدالة ديناميكًا من قالب (في تطبيقات الوِب المعقّدة).
المنغلقات
عادةً ما تتذكّر الدالة مكان ولادتها في الخاصية المميّزة [[Environment]]
، فتُشير إلى البيئة المُعجمية حين صُنعت الدالة (شرحنا هذا في فصل «المُنغِلقات»).
ولكن حين نصنع الدالة باستعمال new Function
فتُضبط خاصية [[Environment]]
على البيئة المُعجمية العمومية لا الحالية.
أي أنّ هذه الدوال لا يمكن أن ترى المتغيرات الخارجية بل تلك العمومية فقط.
function getFunc() { let value = "test"; let func = new Function('alert(value)'); return func; } getFunc()(); // خطأ: value غير معرّف
وازن بين هذا والسلوك الطبيعي:
function getFunc() { let value = "test"; let func = function() { alert(value); }; return func; } getFunc()(); // «test»، من بيئة getFunc المُعجمية
صحيح أنّ الميزة الخاصة للصياغة new Function
غريبة بعض الشيء، ولكنها عمليًا مفيدة جدًا.
تخيّل الآن بأنّنا صنعنا دالة من سلسلة نصية. شيفرة هذه الدالة ليست معروفة ونحن نكتب السكربت (ولهذا لم نستعمل الدوال العادية)، بل ستكون معروفة حين تنفيذه. كما أسلفنا يمكن أن نستلم الدالة من الخادوم أو أيّ مكان آخر.
الآن، على دالتنا هذه التفاعل مع السكربت الرئيس.
لكن ماذا لو أمكن لها أن ترى المتغيرات الخارجية؟
المشكلة هي أنّه قبل أن ننشر شيفرة جافاسكربت لنستعملها، نستعمل المُصغِّرات (minifiers) لضغطها. تقلّص هذه المُصغِّرات حجم الشيفرة بإزالة التعليقات والمسافات الزائدة، كما (وهذا مهم) تُغيّر تسمية المتغيرات المحلية إلى أسماء أقصر.
فمثلًا لو كان في الدالة let userName
فيستبدلها المُصغِّر إلى let a
(أو أيّ حرف آخر لو هناك من أخذ الاسم)، وينفّذ هذا في كلّ مكان آخر. عادةً لا يضرّ ذلك إذ أنّ المتغير محلي ولا يمكن لما خارج الدالة رؤيته، بينما يستبدل المُصغِّر كلّ مرة يرد فيها المتغير داخل الدالة. هذه الأدوات ذكية فهي تحلّل بنية الشيفرة لألا تُعطبها، وليست كأدوات البحث والاستبدال الهمجية.
لذا لو أرادت new Function
أن تستعمل المتغيرات الخارجية فلن تعرف بوجود userName
الذي تغيّر اسمه.
لو أمكن للدوال new Function
أن ترى المتغيرات الخارجية لكانت ستواجه مشاكل جمّة مع المُصغِّرات.
كما وأنّ الشيفرات من هذا النوع ستكون سيّئة من حيث البنية وعُرضة للأخطاء والمشاكل.
لو أردت تمرير شيء للدالة new Function
فعليك استعمال مُعاملاتها.
ملخص
الصياغة:
let func = new Function ([arg1, arg2, ...argN], functionBody);
ويمكن تمرير المُعاملات (لأسباب تاريخية أيضًا) في قائمة مفصولة بفواصل.
هذه التصريحات الثلاث لا تفرق عن بعضها البعض:
new Function('a', 'b', 'return a + b'); // الصياغة الأساس new Function('a,b', 'return a + b'); // مفصولة بفواصل new Function('a , b', 'return a + b'); // مفصولة بفواصل ومسافات
تُشير خاصية [[Environment]]
للدوال new Function
إلى البيئة المُعجمية العمومية لا الخارجية. بهذا لا يمكن لهذه الدوال استعمال المتغيرات الخارجية. إلّا أنّ ذلك أمر طيّب إذ تؤمّن لنا خطّ حماية لألا نصنع الأخطاء والمشاكل، فتمرير المُعاملات جهارةً أفضل بكثير من حيث بنية الشيفرة ولا تتسبّب مشاكل مع المُصغِّرات.
ترجمة -وبتصرف- للفصل The "new Function" syntax من كتاب The JavaScript language
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.