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

الوضع الصارم يقدم بعض التغييرات على دلالات JavaScript. يمنع النظام من التغاضي عن الأخطاء عن طريق رمي الاستثناءات المناسبة. هذا يؤدي تنفيذ البرنامج لإيقاف.
بالإضافة إلى ذلك ، يساعد الوضع الصارم في كتابة البرامج التي لا توجد بها عيوب تمنع محركات JS من تحسين الكود. علاوة على ذلك ، في هذا الوضع ، يُحظر استخدام عناصر بناء الجملة التي قد تحصل على معنى خاص في الإصدارات المستقبلية من اللغة.
ميزات استخدام الوضع الصارم
يمكن تطبيق الوضع الصارم على الوظائف الفردية أو البرنامج النصي بأكمله. لا يمكن تطبيقه فقط على الإرشادات الفردية أو مقاطع الكود المرفقة بأقواس. من أجل استخدام وضع صارم على مستوى البرنامج النصي بالكامل ، في بداية الملف ، قبل أي أوامر أخرى ، تحتاج إلى وضع
"use strict"
أو
'use strict'
بناء
'use strict'
.
إذا كان المشروع يحتوي على بعض البرامج النصية التي لا تستخدم وضعًا صارمًا ، وبعضها الآخر يستخدم هذا الوضع ، فقد يحدث دمج هذه البرامج النصية.
سيؤدي ذلك إلى حقيقة أن التعليمات البرمجية غير المقصود تنفيذها في الوضع الصارم ستكون في مثل هذه الحالة عندما يحاول النظام تنفيذها في الوضع الصارم. العكس هو ممكن أيضا - كود مكتوبة لوضع صارم سوف تقع في وضع غير صارم. لذلك ، من الأفضل عدم خلط النصوص "الصارمة" و "غير الصارمة".
كما ذكرنا سابقًا ، يمكن تطبيق الوضع الصارم على الوظائف الفردية. من أجل القيام بذلك - يجب وضع الإنشاء
"use strict"
أو
'use strict'
في الجزء العلوي من نص الوظيفة ، قبل أي أوامر أخرى. ينطبق الوضع الصارم مع هذه الطريقة على كل ما يتم وضعه في نص الوظيفة ، بما في ذلك الدوال المتداخلة.
على سبيل المثال:
const strictFunction = ()=>{ 'use strict'; const nestedFunction = ()=>{
في وحدات JavaScript التي ظهرت في معيار ES2015 ، يتم تمكين الوضع الصارم افتراضيًا. لذلك ، عند العمل معهم ، لا تحتاج إلى تضمينه بشكل صريح.
التغييرات التي أدخلت على رمز JS بواسطة الوضع الصارم
يؤثر الوضع الصارم على كلٍ من بناء جملة الكود والطريقة التي يتصرف بها الكود أثناء تنفيذ البرنامج. يتم تحويل الأخطاء في التعليمات البرمجية إلى استثناءات. حقيقة أنه في الوضع الهادئ تعطل بهدوء في الوضع الصارم يؤدي رسالة خطأ. هذا مشابه لكيفية استجابة النظام لأخطاء بناء الجملة في وضع lax. في الوضع الصارم ، يتم تبسيط العمل مع المتغيرات ، ويتم تنظيم استخدام الدالة
eval
وكائن
arguments
بإحكام ، كما يتم تبسيط العمل مع التركيبات التي يمكن تنفيذها في الإصدارات المستقبلية من اللغة.
errors تحويل الأخطاء الصامتة إلى استثناءات
يتم تحويل الأخطاء الصامتة في وضع صارم إلى استثناءات. في وضع التراخي ، لا يستجيب النظام صراحة لمثل هذه الأخطاء. في الوضع الصارم ، يؤدي وجود مثل هذه الأخطاء إلى عدم تشغيل التعليمات البرمجية.
لذلك ، بفضل هذا ، من الصعب ارتكاب خطأ التصريح عن متغير عمومي عن طريق الخطأ ، حيث لا يمكن التصريح عن المتغيرات والثوابت في الوضع الصارم دون استخدام توجيهات
var
أو
let
أو
const
. نتيجة لذلك ، سيؤدي إنشاء متغيرات بدون هذه التوجيهات إلى عدم تشغيل البرنامج. على سبيل المثال ، ستؤدي محاولة تنفيذ التعليمة البرمجية التالية إلى استثناء
ReferenceError
:
'use strict'; badVariable = 1;
لا يمكن تشغيل هذا الرمز في الوضع الصارم ، لأنه إذا تم إيقاف تشغيل الوضع الصارم ،
badVariable
ذلك إلى إنشاء متغير
badVariable
. يحمي الوضع الصارم المبرمج من إنشاء متغيرات عمومية دون قصد.
محاولة لتنفيذ أي تعليمات برمجية ، في الوضع العادي ، ببساطة لا يعمل ، الآن استثناء. تعتبر الأخطاء أي إنشاءات بناء جملة غير صحيحة تم تجاهلها ببساطة في وضع التراخي.
لذلك ، على سبيل المثال ، في الوضع الصارم ، لا يمكنك إجراء عمليات تعيين القيمة على كيانات للقراءة فقط مثل
arguments
أو
NaN
أو
eval
.
في الوضع الصارم ، سيتم طرح استثناء ، على سبيل المثال ، في الحالات التالية:
- محاولة لتعيين قيمة لخاصية للقراءة فقط ، مثل بعض أنواع الخصائص العالمية القابلة لإعادة الكتابة ؛
- محاولة لكتابة قيمة إلى خاصية ليس لها سوى getter ؛
- محاولة لكتابة شيء إلى خاصية كائن غير قابل للتوسيع.
فيما يلي أمثلة على بنيات بناء الجملة التي تؤدي إلى استثناءات في الوضع الصارم:
'use strict'; let undefined = 5; let Infinity = 5; let obj = {}; Object.defineProperty(obj, 'foo', { value: 1, writable: false }); obj.foo = 1 let obj2 = { get foo() { return 17; } }; obj2.foo = 2 let fixedObj = {}; Object.preventExtensions(fixedObj); fixed.bar= 1;
ستؤدي محاولة تنفيذ أجزاء التعليمات البرمجية هذه في الوضع الصارم إلى استثناء
TypeError
. على سبيل المثال ،
undefined
و
Infinity
كيانات عمومية لا يمكن الكتابة فوق قيمها ، ولا تدعم خاصية
foo
الخاصة بالكائن
obj
إعادة الكتابة. الخاصية
foo
من
obj2
لديه فقط getter. كائن
fixedObj
قابل للتوسيع باستخدام الأسلوب
Object.preventExtensions
.
سيؤدي أيضًا محاولة حذف
TypeError
غير قابلة
TypeError
إلى
TypeError
:
'use strict'; delete Array.prototype
يحظر الوضع الصارم تخصيص الخصائص التي تحمل الاسم نفسه لكائن ما. نتيجة لذلك ، ستؤدي محاولة تنفيذ التعليمات البرمجية التالية إلى حدوث خطأ في بناء الجملة:
'use strict'; let o = { a: 1, a: 2 };
يتطلب الوضع الصارم أسماء معلمات الدوال لتكون فريدة. في الوضع غير الصارم ، على سبيل المثال ، إذا كان لمعلمتين الوظيفة نفس الاسم
one
، فعند اجتياز دالة الوسيطة ، ستكون قيمة المعلمة هي ما وقع في الوسيطة التي تم إعلانها أخيرًا.
في الوضع الصارم ، يُحظر استخدام معلمات الوظائف التي تحمل الاسم نفسه. نتيجة لذلك ، ستؤدي محاولة تنفيذ التعليمات البرمجية التالية إلى حدوث خطأ في بناء الجملة:
'use strict'; const multiply = (x, x, y) => x*x*y;
في الوضع الصارم ، لا يمكنك استخدام الترميز الثماني للأرقام ، مسبوقًا بالرقم صفر. هذا ليس في المواصفات ، ولكن هذه الميزة تدعمها المتصفحات.
هذه الحالة تخلط بين المطورين ، وتجبرهم على الاعتقاد بأن الرقم الذي يسبق الرقم يتم تجاهله ببساطة ، دون أي معنى. في الوضع الصارم ، ستؤدي محاولة استخدام رقم في البداية يساوي 0 إلى حدوث خطأ في بناء الجملة.
يحظر الوضع الصارم أيضًا استخدام التركيبات التي تعيق التحسين. يجب على المترجم الشفهي ، قبل إجراء تحسين الكود ، معرفة أن المتغير يتم تخزينه بالضبط حيث يتم تخزين المترجم وفقًا للمترجم. في الوضع الصارم ، فإن الأشياء التي تتداخل مع التحسينات محظورة.
أحد الأمثلة على هذا الحظر يتعلق بالبيان. إذا كنت تستخدم هذه التعليمات ، فإن هذا يمنع مترجم JS من معرفة المتغير أو الخاصية التي نشير إليها ، لأنه من الممكن أن يوجد كيان يحمل نفس الاسم خارج وداخل كتلة العبارة ب.
افترض أن هناك كود مثل هذا:
let x = 1; with (obj) { x; }
لن يتمكن المترجم من معرفة ما إذا كان المتغير
x
الموجود داخل الكتل يشير إلى المتغير الخارجي
x
أو إلى خاصية
obj.x
للكائن
obj
.
نتيجة لذلك ، ليس من الواضح أين سيتم تحديد قيمة
x
في الذاكرة. للتخلص من أوجه الغموض هذه ، في الوضع الصارم ، يُحظر استخدام العبارة "
with
. دعونا نرى ما يحدث إذا حاولت تنفيذ التعليمات البرمجية التالية في وضع صارم:
'use strict'; let x = 1; with (obj) { x; }
ستكون نتيجة هذه المحاولة خطأ في بناء الجملة.
حتى في الوضع الصارم ، يُمنع إعلان المتغيرات في الكود
eval
طريقة
eval
.
على سبيل المثال ، في الوضع العادي ، سيؤدي أمر النموذج
eval('let x')
إلى إعلان المتغير
x
. يسمح هذا للمبرمجين بإخفاء التعريفات المتغيرة في السلاسل ، مما قد يؤدي إلى الكتابة فوق تعريفات نفس المتغيرات خارج
eval
.
لمنع هذا ، في الوضع الصارم ، يُمنع إعلان المتغيرات في الكود الذي تم تمريره كسلسلة إلى طريقة
eval
.
يحظر الوضع الصارم أيضًا حذف المتغيرات العادية. نتيجة لذلك ، ستؤدي محاولة تنفيذ التعليمات البرمجية التالية إلى حدوث خطأ في بناء الجملة:
'use strict'; let x; delete x;
construct حظر بناء جملة غير صحيح
في الوضع الصارم ، يُحظر الاستخدام الخاطئ
eval
arguments
. هذا هو الحظر على جميع أنواع التلاعب معهم. على سبيل المثال ، هذا شيء مثل تعيين قيم جديدة لهم ، وذلك باستخدام أسمائهم كأسماء متغيرة ووظائف ومعلمات دالة.
فيما يلي أمثلة لإساءة استخدام
eval
arguments
:
'use strict'; eval = 1; arguments++; arguments--; ++eval; eval--; let obj = { set p(arguments) { } }; let eval; try { } catch (arguments) { } try { } catch (eval) { } function x(eval) { } function arguments() { } let y = function eval() { }; let eval = ()=>{ }; let f = new Function('arguments', "'use strict'; return 1;");
في الوضع الصارم ، لا يمكنك إنشاء أسماء مستعارة لكائن
arguments
وتعيين قيم
arguments
جديدة من خلال هذه الأسماء المستعارة.
في الوضع العادي ، إذا كانت المعلمة الأولى للوظيفة هي ، فإن تعيين قيمة في رمز الوظيفة يؤدي أيضًا إلى تغيير في القيمة في
arguments[0]
. في الوضع الصارم ، ستتضمن
arguments
دائمًا قائمة الوسائط التي تم استدعاء الوظيفة بها.
افترض أن لديك الكود التالي:
const fn = function(a) { 'use strict'; a = 2; return [a, arguments[0]]; } console.log(fn(1))
سوف تحصل على وحدة التحكم
[2,1]
. هذا لأن كتابة قيمة 2 إلى
a
لا يكتب قيمة 2 إلى
arguments[0]
.
performance تحسين الأداء
في الوضع الصارم ، الخاصية
arguments.callee
غير مدعمة. في الوضع العادي ، تقوم بإرجاع اسم الوظيفة الأصل للدالة التي تعترض خاصية
callee
arguments
نقوم بفحصها.
يتداخل دعم هذه الخاصية مع التحسينات ، مثل الدالات المضمّنة ، لأن استخدام
arguments.callee
يتطلب توفر مرجع إلى وظيفة غير مدمجة عند الوصول إلى هذه الخاصية. في الوضع الصارم ، يؤدي استخدام
arguments.callee
إلى استثناء
TypeError
.
في الوضع الصارم ، لا يجب أن تكون
this
كائنًا دائمًا. في الظروف العادية ، إذا كانت
this
الوظيفة مرتبطة أو تستخدم
call
أو
apply
أو
bind
بشيء غير كائن أو بقيمة من نوع بدائي مثل
undefined
أو
null
أو
number
أو
boolean
، فينبغي أن تكون هذه القيمة كائنًا.
إذا تغير سياق
this
الأمر إلى شيء غير كائن ، فسيحل الكائن العمومي مكانه. على سبيل المثال ،
window
. هذا يعني أنه إذا قمت باستدعاء دالة من خلال تعيينها على قيمة ليست كائنًا ، فبدلاً من هذه القيمة ، ستقع إشارة إلى الكائن العمومي في
this
.
النظر في مثال:
'use strict'; function fn() { return this; } console.log(fn() === undefined); console.log(fn.call(2) === 2); console.log(fn.apply(null) === null); console.log(fn.call(undefined) === undefined); console.log(fn.bind(true)() === true);
سيتم إخراج جميع أوامر
console.log
بشكل
true
، لأنه في الوضع الصارم لا يتم استبدال قيمة
this
في الوظيفة تلقائيًا بمرجع إلى الكائن العمومي إذا
this
تعيين
this
على قيمة ليست كائنًا.
▍ التغييرات المتعلقة بالأمان
في الوضع الصارم ، لا يمكنك جعل خصائص وظيفة
caller
arguments
عامة. والحقيقة هي أن
caller
، على سبيل المثال ، يمكن أن يتيح الوصول إلى الوظيفة التي تسمى الوظيفة التي نقوم بالوصول إلى خاصية
caller
.
يقوم كائن
arguments
بتخزين الوسائط التي تم تمريرها إلى الدالة عند استدعائها. على سبيل المثال ، إذا كان لدينا دالة
fn
، فهذا يعني أنه من خلال
fn.caller
يمكنك الوصول إلى الوظيفة التي تسمى الوظيفة ، وباستخدام
fn.arguments
يمكنك رؤية الوسيطات التي تم تمريرها إلى
fn
عند استدعائها.
هذه الميزات تشكل مخاطر أمنية محتملة. نتيجة لذلك ، يُحظر الوصول إلى هذه الخصائص في وضع صارم.
function secretFunction() { 'use strict'; secretFunction.caller; secretFunction.arguments; } function restrictedRunner() { return secretFunction(); } restrictedRunner();
في المثال السابق ، لا يمكننا ، في الوضع الصارم ، الوصول إلى
secretFunction.caller
و
secretFunction.arguments
. الحقيقة هي أنه يمكن استخدام هذه الخصائص للحصول على مكدس من استدعاءات الوظائف. إذا حاولت تشغيل هذا الرمز ، فسيتم
TypeError
استثناء
TypeError
.
في الوضع الصارم ، لا يمكن استخدام المعرفات التي يمكن استخدامها في الإصدارات المستقبلية من JavaScript لتسمية المتغيرات أو خصائص الكائنات. على سبيل المثال ، نحن نتحدث عن المعرفات التالية:
implements
،
interface
،
let
،
package
،
private
،
protected
،
public
،
static
yield
.
في ES2015 وفي الإصدارات الأحدث من المعيار ، أصبحت هذه المعرفات كلمات محجوزة. ولا يمكن استخدامها لتسمية المتغيرات أو الخصائص في الوضع الصارم.
النتائج
الوضع الصارم هو المعيار الموجود لسنوات عديدة. تتمتع بدعم متصفح واسع للغاية. يمكن أن تحدث مشكلات التعليمات البرمجية ذات الوضع الصارم فقط في المستعرضات القديمة ، مثل Internet Explorer.
يجب ألا تواجه المتصفحات الحديثة صعوبة في وضع JavaScript الصارم. نتيجة لذلك ، يمكننا القول أنه يجب استخدام هذا الوضع لمنع الأخطاء "الصامتة" وزيادة أمان التطبيق. يتم تحويل الأخطاء الصامتة إلى استثناءات تعوق تنفيذ البرامج ، وفيما يتعلق بتحسين الأمان ، على سبيل المثال ، يمكن ملاحظة آليات الوضع الصارم التي تقيد
eval
وتمنع الوصول إلى مكدس استدعاء الوظيفة. بالإضافة إلى ذلك ، يسهل استخدام الوضع الصارم تحسين رمز JS للمحرك ويفرض على المبرمج معالجة الكلمات المحجوزة بعناية التي قد تجد استخدامها في الإصدارات المستقبلية من JavaScript.
أعزائي القراء! هل تستخدم وضعًا صارمًا عند كتابة كود JS لمشاريعك؟
