Strict Mode در جاوا اسکریپت

03 اسفند 1397
javascript-strict-mode

با سلام، در این مقاله سعی داریم به صورت شفاف به مبحث strict mode در جاوا اسکریپت بپردازیم و ابهامات پیرامون آن را از بین ببریم.

Strict Mode چیست؟

دستور "use strict" باعث می شود کدهای جاوا اسکریپت شما در strict mode اجرا شوند اما این به چه معنی است؟

دستور "use strict" در ECMAScript 5 معرفی شده و جدید بود. بنابراین در نسخه های قبل از آن، این دستور را نادیده می گیرند. حالت strict mode در واقع حالتی است که در آن کدها با شرایط سخت گیرانه تری اجرا می شوند.

به طور مثال نمی توانید از متغیرهای اظهار نشده/تعریف نشده استفاده کنید.

تمام مرورگر های مدرن از این حالت پشتیبانی می کنند:

Chrome FireFox Edge Safari Opera
13.0 4.0 10.0 6.0 12.1

عدد های جدول بالا مربوط به اولین نسخه ای از مرورگر مذکور هستند که به صورت کامل از دستور "use strict" پشتیبانی می کند.

سوال: چرا از "use strict" استفاده می شود؟

پاسخ: برنامه نویسان اکثرا به این دلیل از حالت strict mode استفاده می کنند که باعث می شود کدهای مرتب تر و استانداردتری بنویسند.

نکته: دستور "use strict" فقط یک رشته است بنابراین در مرورگر هایی که از آن پشتیبانی نمی کنند (مانند Internet Explorer 9) باعث تولید خطا نمی شود.

نحوه ی اعلام strict mode

برای ایجاد حالت strict mode باید از دستور "use strict" در ابتدای اسکریپت یا تابع خود استفاده کنید. اگر در ابتدای اسکریپت نوشته شود دارای global scope می شود بنابراین روی تمام کدهایتان اثر می گذارد. مثال:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Using a variable without declaring it, is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
x = 3.14;
</script>

</body>
</html>

فکر می کنید خروجی این کد چه چیزی باشد؟

درست حدس زدید! خروجی ما یک خطا خواهد بود! چرا؟ به این دلیل که در X در اینجا declare (اظهار) نشده است یعنی مستقیما به آن مقدار دهی شده است. اگر در غیر از حالت strict mode این کار را انجام دهید، جاوا اسکریپت خودش آن متغیر را declare می کند اما نباید این کار را انجام دهید چرا که به هیچ عنوان استاندارد نیست.

می توانید خروجی این کد را در ادیتور آنلاین جاوا اسکریپت مشاهده کنید. البته باید پس از ورود به صفحه ی ادیتور آنلاین، کلید f12 را بزنید و به سربرگ console بروید تا خطا را مشاهده کنید.

به مثالی دیگر توجه کنید. این بار می خواهیم از strict mode به صورت سراسری استفاده کنیم:

<!DOCTYPE html>
<html>
<body>

<h2>Global "use strict" declaration.</h2>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
myFunction();

function myFunction() {
  y = 3.14;
}
</script>

</body>
</html>

خروجی این کد چطور؟ می توانید آن را حدس بزنید؟

بله باز هم به خطا برخورد خواهیم کرد چرا که متغیر y اصلا تعریف نشده است، بلکه مستقیما به آن مقدار داده اید.

مثال بعدی ما مربوط به استفاده از دستور  "use strict" به صورت محلی (local) است:

<!DOCTYPE html>
<html>
<body>

<p>"use strict" in a function will only cause errors in that function.</p>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
x = 3.14;    
myFunction();

function myFunction() {
  "use strict";
  y = 3.14;  
}
</script>

</body>
</html>

همانطور که می بینید دستور "use strict" را داخل خود تابع قرار داده ایم بنابراین قسمتی از کد ما که به این شکل است -> ;x = 3.14 دیگر خطایی نمی دهد چرا که اصلا در strict mode نیست اما قسمتی که درون تابع قرار دارد و به این شکل است -> ;y = 3.14 ، خطا می دهد، چرا که تابع حالت strict mode است.

Strict Mode و مرورگر های قدیمی

اگر در اسکریپت خود از Strict Mode استفاده کنید اما فردی با مرورگر قدیمی از سایت شما بازدید کند چه اتفاقی می افتد؟

نیازی نیست نگران باشید! همانطور که می دانید syntax مربوط به Strict Mode طوری طراحی شده است که تنها یک رشته باشد اما چرا؟ به این دلیل که کامپایل کردن یک literal عددی مثل ;5+4 یا literal رشته ای مانند ;"John Doe" هیچ خطری ندارد، زیرا تبدیل به یک متغیر ناموجود شده و از بین می رود. به همین دلیل تنها کامپایلر های جدید متوجه دستور "use strict"; می شوند و هیچ مشکلی برای مرورگر های قدیمی به وجود نمی آید.

چرا باید از Strict Mode استفاده کنیم؟

در حالت Strict Mode، نوشتن کدهای ایمن آسان تر است. در واقع Strict Mode باعث می شود مسائلی که قبلا "غیر استاندارد" تلقی می شدند به خطا های واقعی تبدیل شوند! تا شما مجبور شوید از کدهای غیر استاندارد دوری کنید.

به طور مثال اگر در حالت عادی نام یک متغیر را اشتباه تایپ کنید، جاوا اسکریپت آن را تبدیل به یک متغیر Global جدید می کند اما در Strict Mode این عمل باعث بروز یک خطا می شود و به این صورت غیر ممکن می شود که اشتباها یک متغیر Global ایجاد کنیم.

همچنین در حالت عادیِ جاوا اسکریپت، اگر به خصوصیاتی که non-writable (یعنی نمی شود چیزی به آن ها نسبت داد یا تغییرشان داد) هستند، مقداری نسبت دهید، هیچ خطا یا هشداری دریافت نمی کنید. این در حالی است که در Strict Mode هر نوع انتساب مقدار به خصوصیاتی (property) که non-writable و یا getter-only باشند، یا خصوصیتی که اصلا وجود نداشته باشد، یا متغیری که وجود نداشته باشد یا شیء ای که وجود نداشته باشد، باعث بروز یک خطا می شود.

در قسمت های قبلی با کلیت مبحث strict mode در جاوا اسکریپت آشنا شدیم. در این قسمت قصد داریم نگاهی به مواردی بیندازیم که با کدنویسی در حالت strict mode غیر فعال می شوند. چه چیز هایی در strict mode غیر مجاز اند؟

متغیرها

استفاده از متغیر ها بدون declare کردن‌شان غیر مجاز است. به مثال زیر توجه کنید:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Using a variable without declaring it, is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
x = 3.14;  //(x is not defined).
</script>

</body>
</html>

خروجی کد بالا یک خطا خواهد بود. چرا؟ به دلیل اینکه متغیر ما declare نشده است و بنابراین از نظر جاوا اسکریپت چنین متغیری وجود ندارد.

مشاهده ی خروجی این کد در ادیتور آنلاین جاوا اسکریپت

نکته: پس از ورود به ادیتور آنلاین جاوا اسکریپت، برای مشاهده ی خطای ایجاد شده باید با کلید f12 به کنسول مرورگر خود بروید.

اشیاء

استفاده از اشیاء بدون Declare کردن‌شان خطا محسوب می شود. به مثال زیر توجه کنید:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Using an object without declaring it, is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
x = {p1:10, p2:20};   // (x is not defined).
</script>

</body>
</html>

خروجی این کد نیز یک خطا خواهد بود.

نکته: یادتان باشد که اشیاء نیز جزو متغیرها محسوب می شوند.

حذف کردن اشیاء یا متغیرها

در جاوا اسکریپت و در حالت عادی می توانیم یک متغیر را delete کنیم اما اگر درحالت Strict mode باشید چنین چیزی مجاز نخواهد بود:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Deleting a variable (or object) is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
var x = 3.14;
delete x;     // This will cause an error 
</script>

</body>
</html>

حذف کردن توابع

در حالت Strict mode غیر مجاز است که مانند متغیرها (و اشیاء) توابع را حذف کنید. به مثال زیر توجه کنید:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Deleting a function is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
function x(p1, p2) {}; 
delete x;        // This will cause an error 
</script>

</body>
</html>

اگر چنین کاری را انجام دهیم با خطای زیر روبرو می شویم:

Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.

دوگانه سازی نام پارامتر ها

در حالت strict mode کپی کردن و دوگانه سازی نام های پارامتر ها غیر مجاز محسوب می شود:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Duplicating a parameter name is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
function x(p1, p1) {};   // This will cause an error 
</script>

</body>
</html>

استفاده از دستگاه اعداد پایه 8

ابتدا باید توضیح بدهم که دستگاه اعداد پایه 8 چیست؛ منظور ما این است که اعداد مبنای 8 پذیرفته نیستند. اعداد مبنای 8 شامل اعداد 0 تا 7 می شوند.

گرچه که به ندرت از این قابلیت استفاده می کنیم اما اگر کنجکاو هستید یک مثال را برایتان آورده ام:

اعداد هشت‌هشتی را می‌توان از اعداد دودویی بدست آورد، به این گونه که به صورت بسته‌های سه‌تایی از سمت راست جدا می‌کنید. برای مثال، معادل باینری عدد دسیمال ۷۴ برابر ۱۰۰۱۰۱۰ است که اگر گروه‌های سه‌تایی جدا کنید - ۰۱۰ | ۰۰۱ | ۰۰۱ - اکتال این عدد برابر ۱۱۲ می‌شود. در این دستگاه اعداد هر خانه توانی از ۸ را دارد. برای مثال عدد ۱۱۲ در پایه ۸:

۱۱۲۸ = ۱ x ۸۲ + ۱ x ۸۱ + ۲ x ۸۰

سوال: آیا این اعداد استفاده ای دارند؟

پاسخ: بله نمی شود که قابلیتی در یک زبان برنامه نویسی باشد که کاملا بی استفاده باشد. این قابلیت برای افراد حرفه ای در نظر گرفته شده است و به کار افراد عادی نمی آید. به طور مثال برای نوشتن network protocol code های 3 بیتی یا کار با permission ها در لینوکس (مانند عدد 0755 در command line) به کار می روند.

مثال از استفاده در حالت strict mode:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Octal numeric literals are not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
var x = 010;   // This will cause an error 
</script>

</body>
</html>

اگر چنین کدی را بنویسید با خطای زیر روبرو خواهید شد:

Uncaught SyntaxError: Octal literals are not allowed in strict mode.

نکته: همچنین نمی توانید اعداد مبنای 8 را escape کنید. کدی مانند کد زیر خطا محسوب می شود:

<script>
"use strict";
var x = "\010";    
</script>

این مورد استفاده های متعددی دارد که در حالت strict mode غیر مجاز هستند. به طور مثال گاهی اوقات برای استفاده از regular expression ها (عبارات با قائده) و در موقعیت های خاص از این نوع اعداد و escape کردن آنها استفاده می کنیم.

تغییر خصوصیات read-only

read-only (به معنی «تنها خواندنی») مقادیر/خصوصیات/ ... ای هستند که تنها قابل خواندن می باشند و اگر سعی کنید آن ها را تغییر دهید با خطا مواجه خواهید شد. به مثال زیر توجه کنید:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Writing to a read-only property is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
var obj = {};
Object.defineProperty(obj, "x", {value:0, writable:false});

obj.x = 3.14;   // This will cause an error
</script>

</body>
</html>

توضیح کد بالا:

  • ابتدا یک شیء به نام obj تعریف کرده ایم.
  • سپس با استفاده از متد defineProperty یک خصوصیت برای آن تعریف کرده ایم و مقدارش را 0 قرار داده ایم.
  • بعد از آن، با استفاده از دستور writable:false آن را به یک خصوصیت read-only تبدیل کرده ایم.
  • در آخر سعی کرده ایم با دستور obj.x = 3.14 مقدارِ آن خصوصیت را تغییر بدهیم که در حالت strict mode غیر مجاز است. بنابراین با خطای زیر روبرو می شویم:

Uncaught TypeError: Cannot assign to read only property 'x' of object '#<Object>'

تغییر خصوصیات get-only

همانطور که حدس می زدید، خصوصیات get-only خصوصیاتی هستند که فقط قابلیت دریافت (get) را دارند و نمی توان آن ها را set کرد. مثال:

<!DOCTYPE html>
<html>
<body>

<h2>With "use strict":</h2>
<h3>Writing to a get-only property is not allowed.</h3>

<p>Activate debugging in your browser (F12) to see the error report.</p>

<script>
"use strict";
var obj = {get x() {return 0} };

obj.x = 3.14;   // This will cause an error
</script>

</body>
</html>

خروجی این کد باز هم یک خطا خواهد بود.

انتخاب نام eval یا arguments برای یک متغیر

در حالت strict mode نمی توانید نام eval را برای متغیر خود انتخاب کنید. مثال:

<script>
"use strict";
var eval = 3.14;    
</script>

این کد با خطای زیر مواجه خواهد شد:

Uncaught SyntaxError: Unexpected eval or arguments in strict mode

این موضوع در مورد arguments نیز صادق است:

<script>
"use strict";
var arguments = 3.14;   // This will cause an error 
</script>

این کد اشتباه است و باعث جلوگیری از اجرای برنامه تان می شود.

کلیدواژه هایی که مخصوص جاوا اسکریپت هستند و از قبل رزرو شده می باشند شامل موارد زیر هستند:

  • implements
  • interface
  • let
  • package
  • private
  • protected
  • public
  • static
  • yield

تحت هیچ شرایطی اجازه ی استفاده از این کلیدواژه ها را به عنوان نام متغیر، شیء و ... ندارید. مثال:

<script>
"use strict";
var public = 1500;    
</script>

نام متغیر یک کلمه ی کلیدی است و بنابراین نمی توان از آن استفاده کرد. خروجی این کد یک خطا خواهد بود.

سوال: اگر کد بالا را به این شکل بنویسیم چطور؟

<script>
var public = 1500; 
"use strict";  
</script>

پاسخ: در این صورت به خطایی برنمیخوریم! چرا که strict mode تنها زمانی اجرایی می شود که در ابتدای سورس کد نوشته شود. در کد بالا strict mode اجرا نخواهد شد و در حالت عادی هستیم (به مقاله ی قسمت قبل رجوع شود).

استفاده از دستور with

استفاده از with در جاوا اسکریپت غیر مجاز است:

<script>
"use strict";
with (Math){x = cos(2)};   // This will cause an error 
</script>

خروجی این کد عبارت زیر خواهد بود:

Uncaught SyntaxError: Strict mode code may not include a with statement

استفاده از تابع ()eval در شرایط خاص

اگر بخواهیم با تابع ()eval متغیری بسازیم که در scope ای یکسان با خود ()eval صدا زده شده است، به خطا برمیخوریم. مثال:

<script>
"use strict";
eval ("var x = 2");
alert (x);      // This will cause an error 
</script>

این کد اشتباه است. چرا؟ به دلیل اینکه در فضای global از eval استفاده کرده ایم و در همان فضا متغیر را صدا زده ایم.

حتی اگر از strict mode استفاده نمی کنید باید سعی کنید در حد امکان موارد بالا را رعایت کنید تا کد شما استاندارد تر باشد. امیدوارم از این قسمت لذت برده باشید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش جاوا اسکریپت | Javascript توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (2 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

mehr
08 آذر 1399
خیلی ممنون که انقدر عالی توضیح میدید به خصوص قسمت قبل خیلی خوب بود لطفا برای این قسمت که مثال هایی که نوشته اید پاسخشان خطا هست طریق صحیح نوشتنشان را هم بنویسید الان من نمیدونم این مثال ها که در این درس آمده در حالت strict mode چجوری باید بنویسم که خطا ندهد

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

علیرضا
20 خرداد 1399
تشکر از مطلب خوبتون

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.