تنفذ الدالّة Eval
المضمّنة في اللغة الشيفرات البرمجية المُمرّرة لها كسلسلة نصية string
.
وصياغتها هكذا:
let result = eval(code);
فمثلًا:
let code = 'alert("Hello")';
eval(code); // Hello
يمكن أن تكون الشيفرة المُمررة للدالّة كبيرة وتحتوي على فواصل أسطر وتعريف دوالّ ومتغيّرات، وما إلى ذلك.
ولكن نتيجة الدالّة Eval
هي نتيجة آخر عبارة منفذة في الشيفرة.
وإليك المثال التالي:
let value = eval('1+1');
alert(value); // 2
let value = eval('let i = 0; ++i');
alert(value); // 1
تُنفذّ الشيفرة في البيئة الحالية للدالّة، ولذا فيمكنها رؤية المتغيرات الخارجية:
let a = 1;
function f() {
let a = 2;
eval('alert(a)'); // 2
}
f();
كما يمكنها تعديل المتغيّرات الخارجية أيضًا:
let x = 5;
eval("x = 10");
alert(x); // النتيجة: 10، تعدلت القيمة بنجاح
في الوضع الصارم، تملك الدالّة Eval
بيئة متغيّرات خاصة بها. لذا فلن تظهر الدوالّ والمتغيرات، المعرفة -داخل الدالة- للخارج وإنما ستبقى بداخلها:
// تذكر أن في الوضع الصارم يُشغّلُ تلقائيًا في الأمثلة الحيّة
eval("let x = 5; function f() {}");
alert(typeof x); // undefined (المتحول غير مرئي هنا)
// الدالّة f غير مرئية هنا أيضًا
بدون تفعيل “الوضع صارم”، لن يكون للدالّة Eval
بيئة متغيرات خاصة بها، ولذلك سنرى المتغيّر x
والدالّة f
من خارج الدالّة.
استخدامات الدالّة “Eval”
في طرق البرمجة الحديثة، نادرًا ما تستخدم الدالّة Eval
. وغالبًا ما يقال عنها أنها أصل الشرور.
والسبب بسيط: إذ كانت لغة جافا سكريبت منذ زمن بعيد أضعف بكثير من الآن، ولم يكُ بالإمكان فعل إيّ شيء إلا باستخدام الدالّة Eval
. ولكن ذلك الوقت مضى عليه عقد من الزمن.
حاليًا، لا يوجد سبب وجيه لاستخدامها. ولو أن شخصًا يستخدمها الآن فلديه الإمكانية لاستبدالها بالبنية الحديثة للغة أو بالوحدات.
لاحظ أن إمكانية وصول الدالة eval
للمتغيرات الخارجية لها عواقب سيئة.
إن عملية تصغير الشيفرة (هي الأدوات تستخدم لتصغير شيفرة جافا سكريبت قبل نشرها وذلك لتصغير حجمها أكثر من ذي قبل) تعيد تسمية المتغيّرات المحلية لأسماء أقصر (مثل a
وb
وما إلى ذلك) لتصغير الشيفرة. وعادةً ما تكون هذه العلمية آمنة، ولكن ليس في حال استخدام الدالّة Eval
، إذ يمكننا الوصول للمتغيّرات المحلية من الشيفرة المُمررة للدالّة. لذا، لن تصغّر المتغيرات التي يحتمل أن تكون مرئية من الدالة Eval
. مما سيُؤثر سلبًا على نسبة ضغط الشيفرة.
يُعدّ استخدام المتغيّرات المحلية في الشيفرة بداخل الدالّة Eval
من الممارسات البرمجية السيئة، لأنه يزيد صعوبة صيانة الشيفرة.
هناك طريقتان لضمان الأمان الكامل عند مصادفتك مثل هذه المشاكل.
إذا لم تستخدم الشيفرة الممررة للدالّة المتغيرات الخارجية، فمن الأفضل استدعاء الدالّة هكذا: window.eval(...)
بهذه الطريقة ستُنفذّ الشيفرة في النطاق العام:
let x = 1;
{
let x = 5;
window.eval('alert(x)'); // 1 (global variable)
}
إن احتاجت الشيفرة الممررة للدالة Eval
لمتغيّرات خارجية، فغيّر Eval
لتصبح new Function
ومرّر المتغير كوسيط. هكذا:
let f = new Function('a', 'alert(a)');
f(5); // 5
شرحنا في مقالٍ سابق تعلمنا كيفية استخدام صياغة «الدالة الجديدة» new Function. إذ باستخدام هذه الصياغة ستُنشأ دالة جديدة من السلسلة (String)، في النطاق العام. لذا لن تتمكن من رؤية المتغيرات المحلية. ولكن من الواضح أن تمريرها المتغيرات صراحة كوسطاء سيحلّ المشكلة، كما رأينا في المثال أعلاه.
خلاصة
سيُشغّل استدعاء الدالّة eval(code)
الشيفرة البرمجية المُمرّرة ويعيد نتيجة العبارة الأخيرة.
- نادرًا ما تستخدم هذه الدالّة في الإصدارات الحديثة للغة، إذ لا توجد حاجة ماسّة لها.
- يمكننا الوصول دائمًا للمتغيّرات الخارجية في الدالّة
eval
. ولكن يعدّ ذلك من الممارسات السيئة. - بدلًا من ذلك يمكننا استخدام الدالة
eval
في النطاق العام، هكذاwindow.eval(code)
. - أو، إذا كانت الشيفرة الخاصة بك تحتاج لبعض البيانات من النطاق الخارجي، فاستخدم صياغة
الدالّة الجديدة
ومرّر لها المتغيرات كوسطاء.
التمارين
آلة حاسبة باستخدام الدالة Eval
الأهمية: 4
أنشئ آلة حاسبة تطالب بتعبير رياضي وتُعيد نتيجته.
لا داعي للتحقق من صحة التعبير في هذا التمرين. فقط قيّم التعبير وأعد نتيجته.
الحل
لنستخدم الدالة eval
لحساب التعبير الرياضي:
let expr = prompt("Type an arithmetic expression?", '2*3+2');
alert( eval(expr) );
يستطيع المستخدم أيضًا إدخال أي نص أو شيفرة.
لجعل الشيفرة آمنة، وحصرها للعمليات الرياضية فحسب، سنتحقق من expr
باستخدام التعابير النمطية، لكي لا تحتوي إلا على الأرقام والمعاملات رياضية.
ترجمة -وبتصرف- للفصل Eval: run a code string من كتاب The JavaScript language
التعليقات
<code>
، وللكثير من السطور استخدم<pre>
، ولأكثر من 10 سطور استخدم (plnkr, JSBin, codepen…)