مهم نیست که چقدر در برنامهنویسی عالی هستیم، گاهی اوقات اسکریپتهای ما ارورهایی (error) دارند. این ارورها ممکن است به دلیل اشتباهات ما، ورودی غیر منتظره کاربر، پاسخ نادرست سرور و هزاران دلیل دیگر رخ بدهند.
معمولا، هنگامی که اروری رخ میدهد اسکریپت میمیرد (بلافاصله متوقف میشود) و آن را در کنسول چاپ میکند.
اما یک ساختار سینتکسی try...catch
وجود دارد که به ما این امکان را میدهد که ارورها را «بگیریم (catch)» تا اسکریپت، به جای مردن، بتواند کاری منطقیتر انجام دهد.
سینتکس “try…catch”
ساختار try...catch
دو بلوک اصلی دارد: try
و سپس catch
:
try {
// ...کد
} catch (err) {
// مدیریت ارور
}
این سینتکس اینگونه کار میکند:
- ابتدا، کد درون
try {...}
اجرا میشود. - اگر اروری وجود نداشت، سپس
catch (err)
نادیده گرفته میشود: اجرای برنامه به انتهایtry
میرسد و با گذشتن ازcatch
ادامه مییابد. - اگر اروری رخ دهد، سپس اجرای
try
متوقف شده و کنترل برنامه به ابتدایcatch (err)
میرود. متغیرerr
(میتوانیم هر نامی برای آن استفاده کنیم) شامل شیء اروری حاوی جزئیاتی درباره چیزی که اتفاق افتاده است.
پس یک ارور درون بلوک try {...}
اسکریپت را نمیکشد – ما شانسی برای مدیریت آن درون catch
داریم.
بیایید به چند مثال نگاهی بیاندازیم.
-
یک مثال بدون ارور:
alert
خطوط(1)
و(2)
را نشان میدهد:try { alert('ابتدای try اجرا میشود'); // (1) <-- // اروری اینجا وجود ندارد... alert('انتهای try اجرا میشود'); // (2) <-- } catch (err) { alert('نادیده گرفته میشود چون اروری وجود ندارد Catch'); // (3) }
-
مثالی شامل یک ارور: خطوط
(1)
و(3)
را نمایش میدهد:try { alert('ابتدای try اجرا میشود'); // (1) <-- lalala; // !ارور، متغیر تعریف نشده است alert('(هیچ گاه به اینجا نمیرسد) try انتهای'); // (2) } catch (err) { alert(`ارور رخ داد!`); // (3) <-- }
try...catch
فقط برای ارورهای هنگام اجرای برنامه کار میکندبرای اینکه try...catch
کار کند، کد باید قابل اجرا باشد. به عبارتی دیگر، باید کد جاوااسکریپت معتبر باشد.
اگر کد از لحاظ سینتکسی غلط باشد کار نمیکند، برای مثال اگر آکولادهای بیهمتا داشته باشد:
try {
{{{{{{{{{{{{
} catch (err) {
alert("موتور جاوااسکریپت نمیتواند این کد را متوجه شود. این کد نامعتبر است.");
}
موتور جاوااسکریپت ابتدا کد را میخواند و سپس آن را اجرا میکند. ارورهایی که در فاز خواندن رخ میدهند، ارورهای «زمان تجزیه (parse-time errors)» نامیده میشوند و قابل پوشش نیستند (از درون همان کد). به این دلیل که موتور نمیتواند کد را متوجه شود.
پس try...catch
تنها میتواند ارورهایی که در کد معتبر رخ میدهند را مدیریت کند. چنین ارورهایی «ارورهای هنگام اجرا (runtime errors)» یا گاهی اوقات «استثناها (exceptions)» نامیده میشوند.
try...catch
به صورت همگام کار میکنداگر یک استثناء در کدی «برنامهریزی شده» رخ دهد، مثلا در setTimeout
، سپس try...catch
آن را نمیگیرد:
try {
setTimeout(function() {
noSuchVariable; // اسکریپت اینجا میمیرد
}, 1000);
} catch (err) {
alert( "کار نخواهد کرد" );
}
به این دلیل که خود تابع بعدا اجرا میشود، زمانی که موتور ساختار try...catch
را پشت سر گذاشته است.
برای اینکه استثناء را درون یک تابع برنامهریزی شده بگیریم، try...catch
باید درون آن تابع باشد:
setTimeout(function() {
try {
noSuchVariable; // !ارور را مدیریت میکند try...catch
} catch {
alert( "ارور اینجا گرفته میشود!" );
}
}, 1000);
شیء Error
زمانی که یک ارور رخ میدهد، جاوااسکریپت شیءای حاوی جزئیاتی درباره آن را ایجاد میکند. این شیء به عنوان آرگومان به catch
پاس داده میشود:
try {
// ...
} catch (err) { // <-- استفاده کنیم err این «شیء ارور» است، میتوانستیم از کلمهای دیگر به جای
// ...
}
برای تمام ارورهای درونساخت، شیء ارور دو ویژگی اصلی دارد:
name
- اسم ارور. برای مثال، برای یک متغیر تعریف نشده برابر با
"ReferenceError"
است. message
- پیام متنی درباره جزئیات ارور.
در اکثر محیطها ویژگیهای غیر استاندارد دیگر هم وجود دارد. یکی از ویژگیهایی که به طور گسترده استفاده و پشتیبانی میشود:
stack
- پشته فراخوانی کنونی: رشتهای حاوی اطلاعاتی درباره دنباله فراخوانیهایی که موجب رخ دادن ارور شدند. برای اهداف اشکالزدایی استفاده میشود.
برای مثال:
try {
lalala; // !ارور، متغیر تعریف نشده است
} catch (err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala is not defined
alert(err.stack); // ReferenceError: lalala is not defined at (...پشته فراخوانیها)
// میتوانستیم ارور را به طور کامل هم نشان دهیم
// به رشته تبدیل میشود «name: message» ارور به صورت
alert(err); // ReferenceError: lalala is not defined
}
پیوند اختیاری «catch»
اگر ما به جزئیات ارور نیازی نداریم، catch
میتواند آن را حذف کند:
try {
// ...
} catch { // <-- (err) بدون
// ...
}
استفاده از “try…catch”
بیایید یک مورد استفاده از try...catch
را در دنیای واقعی ببینیم.
همانطور که از قبل میدانیم، جاوااسکریپت از متد JSON.parse(str) برای خواندن مقدارهایی که به صورت جیسان کدگذاری شدهاند پشتیبانی میکند.
این متد معمولا برای کدبرداری دادهای که از طریق شبکه دریافت شده است، از سرور یا منبعی دیگر، استفاده میشود.
ما داده را دریافت میکنیم و JSON.parse
را اینگونه فراخوانی میکنیم:
let json = '{"name":"John", "age": 30}'; // داده دریافت شده از سرور
let user = JSON.parse(json); // تبدیل نمایش متنی به شیء جاوااسکریپت
// شیءای حاوی ویژگیهای دریافت شده از رشته است user حالا
alert( user.name ); // John
alert( user.age ); // 30
شما میتوانید در فصل متدهای JSON، toJSON اطلاعاتی با جزئیات بیشتر درباره جیسان پیدا کنید.
اگر json
شکل درستی نداشته باشد، JSON.parse
یک ارور ایجاد میکند، پس اسکریپت «میمیرد».
آیا ما باید به آن راضی باشیم؟ قطعا نه!
اینگونه، اگر داده مشکلی داشته باشد، بازدید کننده هرگز آن را نخواهد دانست (مگر اینکه آنها کنسول توسعهدهنده را باز کنند). و مردم چیزی که بدون پیام اروری «میمیرد» را دوست ندارند.
بیایید از try...catch
برای مدیریت ارور استفاده کنیم:
let json = "{ bad json }";
try {
let user = JSON.parse(json); // <-- ...زمانی که اروری رخ میدهد
alert( user.name ); // کار نمیکند
} catch (err) {
// اجرای برنامه به اینجا میپرد...
alert( "پوزش میخواهیم، داده دارای ارور است، ما سعی خواهیم کرد یک بار دیگر برای آن درخواست کنیم." );
alert( err.name );
alert( err.message );
}
اینجا ما از بلوک catch
فقط برای نمایش پیام استفاده میکنیم، اما میتوانیم کارهای بیشتری انجام دهیم: یک درخواست شبکه جدید ارسال کنیم، یک راه جایگزین به بازدیدکننده پیشنهاد کنیم، اطلاعاتی درباره ارور را به logging facility ارسال کنیم و… . هر چیزی از مردن بهتر است.
پرتاب ارورهای خودمان
اگر json
از لحاظ سینتکس درست باشد اما ویژگی مورد نیاز name
را نداشته باشد چه؟
مثل اینجا:
let json = '{ "age": 30 }'; // داده ناقض
try {
let user = JSON.parse(json); // <-- اروری وجود ندارد
alert( user.name ); // !وجود ندارد name ویژگی
} catch (err) {
alert( "اجرا نمیشود" );
}
اینجا JSON.parse
به صورت طبیعی اجرا میشود اما در واقع نبودن name
برای ما یک ارور است.
برای یکی کردن مدیریت ارور، ما از عملگر throw
استفاده میکنیم.
عملگر «Throw»
عملگر throw
(به معنی پرتاب کردن) یک ارور ایجاد میکند.
سینتکس آن:
throw <error object>
از لحاظ فنی ما میتوانیم از هر چیزی به عنوان شیء ارور استفاده کنیم. حتی ارور میتواند یک مقدار اصلی باشد،مثل یک عدد یا رشته، اما بهتر است از شیءها استفاده کنیم که ترجیحا ویژگیهای name
و message
را داشته باشند (برای اینکه تا حدی با ارورهای درونساخت سازگار باشند).
جاوااسکریپت تابعهای سازنده درونساخت زیادی برای ارورهای استاندارد دارد: Error
، SyntaxError
، ReferenceError
، TypeError
و بقیه آنها. ما میتوانیم از آنها برای ایجاد شیءهای ارور هم استفاده کنیم.
سینتکس آنها:
let error = new Error(message);
// یا
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...
برای ارورهای درونساخت (نه برای هر شیءای، فقط برای ارورها)، ویژگی name
دقیقا اسم سازنده است. و message
از آرگومان گرفته میشود.
برای مثال:
let error = new Error("اتفاقاتی رخ میدهد o_O");
alert(error.name); // Error
alert(error.message); // o_O اتفاقاتی رخ میدهد
بیایید ببینیم JSON.parse
چه نوع اروری ایجاد میکند:
try {
JSON.parse("{ bad json o_O }");
} catch (err) {
alert(err.name); // SyntaxError
alert(err.message); // Unexpected token b in JSON at position 2
}
همانطور که میبینیم یک SyntaxError
است.
و در این مورد ما، نبودن name
یک ارور است چون کاربران باید یک name
داشته باشند.
پس بیایید آن را throw کنیم:
let json = '{ "age": 30 }'; // داده ناقص
try {
let user = JSON.parse(json); // <-- اروری وجود ندارد
if (!user.name) {
throw new SyntaxError("Incomplete data: no name"); // (*)
}
alert( user.name );
} catch (err) {
alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name
}
در خط (*)
، عملگر throw
با message
داده شده یک SyntaxError
ایجاد میکند، به همان شیوه که جاوااسکریپت خودش این ارور را ایجاد میکند. اجرای try
بلافاصله متوقف میشود و کنترل به catch
میپرد.
حالا catch
به جایی برای مدیریت تمام ارورها تبدیل شد: هم برای JSON.parse` و هم برای موارد دیگر.
پرتاب دوباره (Rethrowing)
در مثال بالا ما از try...catch
برای مدیریت داده نادرست استفاده میکنیم. اما آیا ممکن است که ارور غیر منتظره دیگری درون بلوک try{...}
رخ دهد؟ مثلا یک ارور برنامهنویسی (متغیر تعریف نشده باشد) یا چیز دیگری، نه فقط موضوع «داده نادرست».
برای مثال:
let json = '{ "age": 30 }'; // داده ناقص
try {
user = JSON.parse(json); // را قرار دهیم «let» کلمه user یادمان رفت که قبل از
// ...
} catch (err) {
alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
// (نیست JSON Error در واقع)
}
قطعا، هر چیزی ممکن است! برنامهنویسان حتما اشتباهاتی میکنند. حتی در تسهیلات متنباز (open-source) که برای دهها سال میلیونها بار استفاده شدهاند – ناگهان یک خطا یا باگ (bug) ممکن است کشف شود که منجر به رخنههای وحشتناک میشود.
در این مورد ما، try...catch
برای گرفتن ارورهای «داده نادرست» قرار داده شده است.اما به خاطر ذات آن، catch
تمام ارورها را از try
دریافت میکند. اینجا، این بلوک یک ارور غیر منتظره دریافت میکند اما هنوز پیام "JSON Error"
یکسان را نشان میدهد. این غلط است و همچنین اشکالزدایی کد را دشوارتر میکند.
برای جلوگیری از چنین مشکلاتی، میتوانیم تکنیک «پرتاب دوباره (rethrowing)» را به کار ببریم. قانون ساده است:
بلوک catch فقط باید ارورهایی را پردازش کند که آنها را میشناسد و بقیه آنها را «rethrow» کند.
تکنیک «rethrowing» میتواند میتواند اینگونه با جزئیات بیشتری توضیح داده شود:
- تمام ارورها را دریافت کن.
- در بلوک
catch (err) {...}
ما شیء ارورerr
را آنالیز میکنیم. - اگر نمیدانیم که چگونه آن را مدیریت کنیم،
throw err
را انجام میدهیم.
معمولا، میتوانیم با استفاده از عملگر instanceof
نوع ارور را بررسی کنیم:
try {
user = { /*...*/ };
} catch (err) {
if (err instanceof ReferenceError) {
alert('ReferenceError'); // برای دسترسی به یک متغیر تعریف نشده «ReferenceError»
}
}
همچنین میتوانیم از ویژگی err.name
اسم کلاس ارور را دریافت کنیم. تمام ارورهای نیتیو (برای خود زبان) آن را دارند. گزینه دیگر خواندن err.constructor.name
است.
در کد پایین، ما از rethrowing استفاده میکنیم تا catch
فقط SyntaxError
را مدیریت کند:
let json = '{ "age": 30 }'; // داده ناقص
try {
let user = JSON.parse(json);
if (!user.name) {
throw new SyntaxError("Incomplete data: no name");
}
blabla(); // ارور غیر منتظره
alert( user.name );
} catch (err) {
if (err instanceof SyntaxError) {
alert( "JSON Error: " + err.message );
} else {
throw err; // rethrow (*)
}
}
پرتاب ارور در خط (*)
از درون بلوک catch
، از try...catch
«بیرون میافتد» و میتواند توسط یک ساختار try...catch
بیرونی گرفته شود (اگر وجود داشته باشد) یا اسکریپت را بکشد.
پس بلوک catch
در واقع فقط ارورهایی که میداند چگونه با آنها مدارا کند را مدیریت میکند و بقیه ارورها را «از قلم میاندازد».
مثال پایین نشان میدهد که چنین ارورهایی چگونه میتوانند توسط یک سطح بالاتر از try...catch
گرفته شوند:
function readData() {
let json = '{ "age": 30 }';
try {
// ...
blabla(); // !ارور
} catch (err) {
// ...
if (!(err instanceof SyntaxError)) {
throw err; // rethrow (نمیدانیم چگونه آن را کنترل کنیم)
}
}
}
try {
readData();
} catch (err) {
alert( "External catch got: " + err ); // !آن را گرفتیم
}
اینجا readData
فقط میداند که SyntaxError
را چگونه مدیریت کند در حالی که try...catch
بیرونی میداند چگونه همه چیز را مدیریت کند.
ساختار try…catch…finally
صبر کنید، این همه چیز نیست.
ساختار try...catch
میتواند یک بند دیگر از کد هم داشته باشد: finally
.
اگر این بند وجود داشته باشد، در تمام موارد اجرا میشود:
- بعد از
try
، اگر اروری وجود نداشته باشد، - بعد از
catch
، اگر اروری وجود داشته باشد.
سینتکس گسترده اینگونه به نظر میرسد:
try {
... سعی در اجرای کد ...
} catch (err) {
... مدیریت ارورها ...
} finally {
... همیشه اجرا میشود ...
}
سعی کنید این کد را اجرا کنید:
try {
alert( 'try' );
if (confirm('ارور ایجاد کنیم؟')) BAD_CODE();
} catch (err) {
alert( 'catch' );
} finally {
alert( 'finally' );
}
این کد 2 راه برای اجرا دارد:
- اگر به سوال «ارور ایجاد کنیم؟» جواب «بله» دهید، سپس
try -> catch -> finally
. - اگر شما «نه» بگویید، سپس
try -> finally
.
بند finally
اغلب زمانی استفاده میشود که ما انجام کاری را شروع میکنیم و میخواهیم با هر نتیجهای آن را به پایان برسانیم.
برای مثال، ما میخواهیم زمانی که یک تابع اعداد فیبوناچی fib(n)
میگیرد را محاسبه کنیم. طبیعتا، ما میتوانیم قبل از اینکه اجرا شود اندازهگیری را آغاز کنیم و سپس آن را تمام کنیم. اما اگر در حین فراخوانی تابع ارور ایجاد شود چه؟ به خصوص در کد پایین، پیادهسازی fib(n)
به ازای اعداد منفی یا غیر صحیح یک ارور برمیگرداند.
بند finally
مکانی عالی برای اتمام اندازهگیریها است؛ هر اتفاقی که بیوفتد.
اینجا finally
تضمین میکند که زمان در هر دو وضعیت به درستی اندازهگیری میشود – در وضعیتی که اجرای fib
موفقیتآمیز باشد و در وضعیتی که اروری درون آن باشد:
let num = +prompt("یک عدد مثبت وارد کنید.", 35)
let diff, result;
function fib(n) {
if (n < 0 || Math.trunc(n) != n) {
throw new Error("نباید منفی باشد، همچنین عدد صحیح قابل قبول است.");
}
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}
let start = Date.now();
try {
result = fib(num);
} catch (err) {
result = 0;
} finally {
diff = Date.now() - start;
}
alert(result || "اروری رخ داد");
alert( `اجرای کد ${diff} میلیثانیه طول کشید.` );
شما میتوانید با اجرای کد بالا همراه با وارد کردن 35
درون prompt
بررسی کنید – کد به صورت معمولی اجرا میشود، finally
بعد از try
. سپس 1-
را وارد کنید – بلافاصله ارور ایجاد میشود و اجرای کد 0ms
طول میکشد. هر دو اندازهگیری به درستی انجام شدهاند.
به عبارتی دیگر، تابع میتواند با return
یا throw
به اتمام برسد، این موضوع مهم نیست. بند finally
در هر دو مورد اجرا میشود.
try...catch...finally
محلی هستندلطفا در نظر داشته باشید که در کد بالا متغیرهای result
و diff
قبل از try...catch
تعریف شدهاند.
در غیر این صورت، اگر ما let
را درون بلوک try
تعریف میکردیم، این متغیر فقط درون همان بلوک قابل رویت بود.
finally
و return
بند finally
برای تمام خارجشدنها از try...catch
کار میکند. این موضوع شامل یک return
واضح هم میشود.
در مثال پایین، یک return
درون try
وجود دارد. در این صورت، finally
درست قبل از اینکه کنترل به کد بیرونی برگردد اجرا میشود.
function func() {
try {
return 1;
} catch (err) {
/* ... */
} finally {
alert( 'finally' );
}
}
alert( func() ); // کار میکند و سپس این یکی finally درون alert اول
try...finally
ساختار try...finally
، بدون بند catch
، هم مفید است. ما زمانی که نمیخواهیم ارورها را مدیریت کنیم (میگذاریم رخ دهند) اما میخواهیم مطمئن باشیم فرایندهایی که شروع کردیم پایان مییابند آن را اعمال میکنیم.
function func() {
// شروع انجام چیزی که به کامل شدن نیاز دارد (مثل اندازهگیریها)
try {
// ...
} finally {
// کامل کردن آن حتی اگر همه چیز بمیرد
}
}
در کد بالا، همیشه یک ارور از داخل try
بیرون میآید چون catch
وجود ندارد. اما قبل از اینکه جریان اجرای برنامه از تابع بیرون بیاید finally
کار میکند.
catch گلوبال
اطلاعات این قسمت بخشی از جاوااسکریپت اصلی نیست.
بیایید فرض کنیم که بیرون از try...catch
یک ارور مهلک رخ داده است و اسکریپت میمیرد. مثلا یک ارور برنامهنویسی یا یک چیز وحشتناک دیگر.
آیا راهی برای واکنش به چنین اتفاقاتی وجود دارد؟ ممکن است ما بخواهیم ارور را رخدادنگاری کنیم، چیزی را به کاربر نمایش دهیم (معمولا آنها پیامهای ارور را نمیبینند) و غیره.
درون مشخصات زبان راهی وجود ندارد اما محیطهای اجرا معمولا راهی را فراهم میکنند چون این کار بسیار مفید است. برای مثال، Node.js برای این کار process.on("uncaughtException")
را دارد. و در مرورگر ما میتوانیم به ویژگی مخصوص window.onerror یک تابع اختصاص دهیم که در صورت رخ دادن یک ارور کنترل نشده اجرا شود.
The syntax:
window.onerror = function(message, url, line, col, error) {
// ...
};
message
- پیام ارور.
url
- URL اسکریپتی که ارور در آنجا رخ داده است.
line
،col
- اعداد خط و ستون که ارور در آنجا رخ داده است.
error
- شیء ارور.
برای مثال:
<script>
window.onerror = function(message, url, line, col, error) {
alert(`${message}\n At ${line}:${col} of ${url}`);
};
function readData() {
badFunc(); // !اوه، یک جای کار میلنگد
}
readData();
</script>
معمولا نقش کنترلکننده گلوبال window.onerror
این نیست که اجرای اسکریپت را ترمیم کند – این موضوع در صورتی که ارور برنامهنویسی وجود داشته باشد احتمالا غیر ممکن است اما فرستادن پیام ارور به توسعهدهندگان ممکن است.
همچنین سرویسهای وب وجود دارند که رخدادنگاری ارور را برای چنین مواردی فراهم میکنند مانند https://errorception.com یا http://www.muscula.com.
آنها اینگونه کار میکنند:
- ما در سرویس ثبت نام میکنیم و از آنها تکهای از کد جاوااسکریپت (یا یک URL اسکریپت) برای اضافه کردن به صفحات دریافت میکنیم.
- آن کد جاوااسکریپت یک تابع
window.onerror
شخصیسازی شده را تنظیم میکند. - زمانی که اروری رخ میدهد، این تابع درباره آن ارور، یک درخواست شبکه را به سرویس ارسال میکند.
- ما میتوانیم وارد رابط وب سرویس شویم و ارورها را ببینیم.
خلاصه
ساختار try...catch
مدیریت ارورهای زمان اجرا را ممکن میسازد. این ساختار به طور لفظی اجازه میدهد که اجرای کد را «امتحان کنیم (try)» و ارورهایی که ممکن است درون آن رخ بدهند را «بگیریم (catch)».
سینتکس آن:
try {
// این کد را اجرا کن
} catch (err) {
// اگر اروری رخ داد، سپس به اینجا بپر
// شیء ارور است err
} finally {
// این قسمت را انجام بده try/catch در هر صورت، بعد از
}
ممکن است قسمت catch
یا finally
وجود نداشته باشد پس ساختارهای کوتاهتر try...catch
و try...finally
هم معتبر هستند.
شیءهای ارور ویژگیهای پایین را دارند:
message
– پیام ارور که برای انسان قابل خواندن است.name
– رشته حاوی اسم ارور (اسم تابع سازنده ارور)stack
(استاندارد نیست، اما به خوبی پشتیبانی میشود) – پشتهای که در لحظه ایجاد ارور وجود دارد.
اگر شیء ارور نیاز نباشد، ما میتوانیم با استفاده از catch {
به جای catch (err) {
آن را حذف کنیم.
همچنین میتوانیم با استفاده از عملگر throw
ارورهای خودمان را ایجاد کنیم. از لحاظ فنی، آرگومان throw
میتواند هر چیزی باشد اما معمولا یک شیء ارور است که از کلاس درونساخت Error
ارثبری میکند. اطلاعات بیشتری درباره تعمیم دادن ارورها در فصل بعدی وجود دارد.
پرتاب دوباره (rethrowing) یک الگوی بسیار مهم در مدیریت ارور است: یک بلوک catch
معمولا توقع یک نوع ارور خاص را دارد و میتواند چجوری آن را مدیریت کند پس باید ارورهایی که آنها را نمیشناسد را دوباره پرتاب کند.
حتی اگر ما try...catch
نداشته باشیم، اکثر محیطهای اجرا به ما اجازه میدهند که یک کنترلکننده ارور «گلوبال» را برای گرفتن ارورهایی که «بیرون میافتند» بسازیم. در مرورگر window.onerror
همان کنترلکننده است.