91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中BUG和錯誤怎么辦

發布時間:2021-07-13 15:34:22 來源:億速云 閱讀:122 作者:小新 欄目:web開發

小編給大家分享一下JavaScript中BUG和錯誤怎么辦,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

計算機程序中的缺陷通常稱為 bug。 它讓程序員覺得很好,將它們想象成小事,只是碰巧進入我們的作品。 實際上,當然,我們自己把它們放在了那里。

如果一個程序是思想的結晶,你可以粗略地將錯誤分為因為思想混亂引起的錯誤,以及思想轉換為代碼時引入的錯誤。 前者通常比后者更難診斷和修復。

語言

計算機能夠自動地向我們指出許多錯誤,如果它足夠了解我們正在嘗試做什么。 但是這里 JavaScript 的寬松是一個障礙。 它的綁定和屬性概念很模糊,在實際運行程序之前很少會發現拼寫錯誤。 即使這樣,它也允許你做一些不會報錯的無意義的事情,比如計算true *'monkey'。

JavaScript 有一些報錯的事情。 編寫不符合語言語法的程序會立即使計算機報錯。 其他的東西,比如調用不是函數的東西,或者在未定義的值上查找屬性,會導致在程序嘗試執行操作時報告錯誤。

不過,JavaScript 在處理無意義的計算時,會僅僅返回NaN(表示不是數字)或undefined這樣的結果。程序會認為其執行的代碼毫無問題并順利運行下去,要等到隨后的運行過程中才會出現問題,而此時已經有許多函數使用了這個無意義的值。程序執行中也可能不會遇到任何錯誤,只會產生錯誤的程序輸出。找出這類錯誤的源頭是非常困難的。

我們將查找程序中的錯誤或者 bug 的過程稱為調試(debug)。

嚴格模式

當啟用了嚴格模式(strict mode)后,JavaScript 就會在執行代碼時變得更為嚴格。我們只需在文件或函數體頂部放置字符串"use strict"就可以啟用嚴格模式了。下面是示例代碼:

function canYouSpotTheProblem() {
 "use strict";
 for (counter = 0; counter < 10; counter++) {
 console.log("Happy happy");
 }
}

canYouSpotTheProblem();
// → ReferenceError: counter is not defined

通常,當你忘記在綁定前面放置let時,就像在示例中的counter一樣,JavaScript 靜靜地創建一個全局綁定并使用它。 在嚴格模式下,它會報告錯誤。 這非常有幫助。 但是,應該指出的是,當綁定已經作為全局綁定存在時,這是行不通的。 在這種情況下,循環仍然會悄悄地覆蓋綁定的值。

嚴格模式中的另一個變化是,在未被作為方法而調用的函數中,this綁定持有值undefined。 當在嚴格模式之外進行這樣的調用時,this引用全局作用域對象,該對象的屬性是全局綁定。 因此,如果你在嚴格模式下不小心錯誤地調用方法或構造器,JavaScript 會在嘗試從this讀取某些內容時產生錯誤,而不是愉快地寫入全局作用域。

例如,考慮下面的代碼,該代碼不帶new關鍵字調用構造器,以便其this不會引用新構造的對象:

function Person(name) { this.name = name; }
let ferdinand = Person("Ferdinand"); // oops
console.log(name);
// → Ferdinand

雖然我們錯誤調用了Person,代碼也可以執行成功,但會返回一個未定義值,并創建名為name的全局綁定。而在嚴格模式中,結果就不同了。

"use strict";
function Person(name) { this.name = name; }
let ferdinand = Person("Ferdinand");
// → TypeError: Cannot set property 'name' of undefined

JavaScript 會立即告知我們代碼中包含錯誤。這種特性十分有用。

幸運的是,使用class符號創建的構造器,如果在不使用new來調用,則始終會報錯,即使在非嚴格模式下也不會產生問題。

嚴格模式做了更多的事情。 它不允許使用同一名稱給函數賦多個參數,并且完全刪除某些有問題的語言特性(例如with語句,這是錯誤的,本書不會進一步討論)。

簡而言之,在程序頂部放置"use strict"很少會有問題,并且可能會幫助你發現問題。

類型

有些語言甚至在運行程序之前想要知道,所有綁定和表達式的類型。 當類型以不一致的方式使用時,他們會馬上告訴你。 JavaScript 只在實際運行程序時考慮類型,即使經常嘗試將值隱式轉換為它預期的類型,所以它沒有多大幫助。

盡管如此,類型為討論程序提供了一個有用的框架。 許多錯誤來自于值的類型的困惑,它們進入或來自一個函數。 如果你把這些信息寫下來,你不太可能會感到困惑。

你可以在上一章的goalOrientedRobot函數上面,添加一個像這樣的注釋來描述它的類型。

// (WorldState, Array) → {direction: string, memory: Array}
function goalOrientedRobot(state, memory) {
 // ...
}

有許多不同的約定,用于標注 JavaScript 程序的類型。

關于類型的一點是,他們需要引入自己的復雜性,以便能夠描述足夠有用的代碼。 你認為從數組中返回一個隨機元素的randomPick函數的類型是什么? 你需要引入一個綁定類型T,它可以代表任何類型,這樣你就可以給予randomPick一個像([T])->T的類型(從T到T的數組的函數)。

當程序的類型已知時,計算機可以為你檢查它們,在程序運行之前指出錯誤。 有幾種 JavaScript 語言為語言添加類型并檢查它們。 最流行的稱為 TypeScript。 如果你有興趣為你的程序添加更多的嚴謹性,我建議你嘗試一下。

在本書中,我們將繼續使用原始的,危險的,非類型化的 JavaScript 代碼。

測試

如果語言不會幫助我們發現錯誤,我們將不得不努力找到它們:通過運行程序并查看它是否正確執行。

一次又一次地手動操作,是一個非常糟糕的主意。 這不僅令人討厭,而且也往往是無效的,因為每次改變時都需要花費太多時間來詳盡地測試所有內容。

計算機擅長重復性任務,測試是理想的重復性任務。 自動化測試是編寫測試另一個程序的程序的過程。 編寫測試比手工測試有更多的工作,但是一旦你完成了它,你就會獲得一種超能力:它只需要幾秒鐘就可以驗證,你的程序在你編寫為其測試的所有情況下都能正常運行。 當你破壞某些東西時,你會立即注意到,而不是在稍后的時間里隨機地碰到它。

測試通常采用小標簽程序的形式來驗證代碼的某些方面。 例如,一組(標準的,可能已經由其他人測試過)toUpperCase方法的測試可能如下:

function test(label, body) {
 if (!body()) console.log(`Failed: ${label}`);
}

test("convert Latin text to uppercase", () => {
 return "hello".toUpperCase() == "HELLO";
});
test("convert Greek text to uppercase", () => {
 return "Χα?ρετε".toUpperCase() == "ΧΑ?ΡΕΤΕ";
});
test("don't convert case-less characters", () => {
 return "?????".toUpperCase() == "?????";
});

像這樣寫測試往往會產生很多重復,笨拙的代碼。 幸運的是,有些軟件通過提供適合于表達測試的語言(以函數和方法的形式),并在測試失敗時輸出豐富的信息來幫助你構建和運行測試集合(測試套件,test suite)。 這些通常被稱為測試運行器(test runner)。

一些代碼比其他代碼更容易測試。 通常,代碼與外部交互的對象越多,建立用于測試它的上下文就越困難。 上一章中顯示的編程風格,使用自包含的持久值而不是更改對象,通常很容易測試。

調試

當程序的運行結果不符合預期或在運行過程中產生錯誤時,你就會注意到程序出現問題了,下一步就是要推斷問題出在什么地方。

有時錯誤很明顯。錯誤消息會指出錯誤出現在程序的哪一行,只要稍加閱讀錯誤描述及出錯的那行代碼,你一般就知道如何修正錯誤了。

但不總是這樣。 有時觸發問題的行,只是第一個地方,它以無效方式使用其他地方產生的奇怪的值。 如果你在前幾章中已經解決了練習,你可能已經遇到過這種情況。

下面的示例代碼嘗試將一個整數轉換成給定進制表示的字符串(十進制、二進制等),其原理是:不斷循環取出最后一位數字,并將其除以基數(將最后一位數從數字中除去)。但該程序目前的輸出表明程序中是存在bug的。

function numberToString(n, base = 10) {
 let result = "", sign = "";
 if (n < 0) {
 sign = "-";
 n = -n;
 }
 do {
 result = String(n % base) + result;
 n /= base;
 } while (n > 0);
 return sign + result;
}
console.log(numberToString(13, 10));
// → 1.5e-3231.3e-3221.3e-3211.3e-3201.3e-3191.3e-3181.3…

你可能已經發現程序運行結果不對了,不過先暫時裝作不知道。我們知道程序運行出了問題,試圖找出其原因。

這是一個地方,你必須抵制隨機更改代碼來查看它是否變得更好的沖動。 相反,要思考。 分析正在發生的事情,并提出為什么可能發生的理論。 然后,再做一些觀察來檢驗這個理論 - 或者,如果你還沒有理論,可以進一步觀察來幫助你想出一個理論。

有目的地在程序中使用console.log來查看程序當前的運行狀態,是一種不錯的獲取額外信息的方法。在本例中,我們希望n的值依次變為 13,1,然后是 0。讓我們先在循環起始處輸出n的值。

13
1.3
0.13
0.013
…
1.5e-323

沒錯。13 除以 10 并不會產生整數。我們不應該使用n/=base,而應該使用n=Math.floor(n/base),使數字“右移”,這才是我們實際想要的結果。

使用console.log來查看程序行為的替代方法,是使用瀏覽器的調試器(debugger)功能。 瀏覽器可以在代碼的特定行上設置斷點(breakpoint)。 當程序執行到帶有斷點的行時,它會暫停,并且你可以檢查該點的綁定值。 我不會詳細討論,因為調試器在不同瀏覽器上有所不同,但請查看瀏覽器的開發人員工具或在 Web 上搜索來獲取更多信息。

設置斷點的另一種方法,是在程序中包含一個debugger語句(僅由該關鍵字組成)。 如果你的瀏覽器的開發人員工具是激活的,則只要程序達到這個語句,程序就會暫停。

錯誤傳播

不幸的是,程序員不可能避免所有問題。 如果你的程序以任何方式與外部世界進行通信,則可能會導致輸入格式錯誤,工作負荷過重或網絡故障。

如果你只為自己編程,那么你就可以忽略這些問題直到它們發生。 但是如果你創建了一些將被其他人使用的東西,你通常希望程序比只是崩潰做得更好。 有時候,正確的做法是不擇手段地繼續運行。 在其他情況下,最好向用戶報告出了什么問題然后放棄。 但無論在哪種情況下,該程序都必須積極采取措施來回應問題。

假設你有一個函數promptInteger,要求用戶輸入一個整數并返回它。 如果用戶輸入"orange",它應該返回什么?

一種辦法是返回一個特殊值,通常會使用null,undefined或 -1。

function promptNumber(question) {
 let result = Number(prompt(question, ""));
 if (Number.isNaN(result)) return null;
 else return result;
}

console.log(promptNumber("How many trees do you see?"));

現在,調用promptNumber的任何代碼都必須檢查是否實際讀取了數字,否則必須以某種方式恢復 - 也許再次詢問或填充默認值。 或者它可能會再次向它的調用者返回一個特殊值,表示它未能完成所要求的操作。

在很多情況下,當錯誤很常見并且調用者應該明確地考慮它們時,返回特殊值是表示錯誤的好方法。 但它確實有其不利之處。 首先,如果函數已經可能返回每一種可能的值呢? 在這樣的函數中,你必須做一些事情,比如將結果包裝在一個對象中,以便能夠區分成功與失敗。

function lastElement(array) {
 if (array.length == 0) {
 return {failed: true};
 } else {
 return {element: array[array.length - 1]};
 }
}

返回特殊值的第二個問題是它可能產生非常笨拙的代碼。 如果一段代碼調用promptNumber 10 次,則必須檢查是否返回null 10 次。 如果它對null的回應是簡單地返回null本身,函數的調用者將不得不去檢查它,以此類推。

異常

當函數無法正常工作時,我們只希望停止當前任務,并立即跳轉到負責處理問題的位置。這就是異常處理的功能。

異常是一種當代碼執行中遇到問題時,可以觸發(或拋出)異常的機制,異常只是一個普通的值。觸發異常類似于從函數中強制返回:異常不只跳出到當前函數中,還會跳出函數調用方,直到當前執行流初次調用函數的位置。這種方式被稱為“堆棧展開(Unwinding the Stack)”。你可能還記得我們在第3章中介紹的函數調用棧,異常會減小堆棧的尺寸,并丟棄所有在縮減程序棧尺寸過程中遇到的函數調用上下文。

如果異常總是會將堆棧尺寸縮減到棧底,那么異常也就毫無用處了。它只不過是換了一種方式來徹底破壞你的程序罷了。異常真正強大的地方在于你可以在堆棧上設置一個“障礙物”,當異常縮減堆棧到達這個位置時會被捕獲。一旦發現異常,你可以使用它來解決問題,然后繼續運行該程序。

function promptDirection(question) {
 let result = prompt(question, "");
 if (result.toLowerCase() == "left") return "L";
 if (result.toLowerCase() == "right") return "R";
 throw new Error("Invalid direction: " + result);
}

function look() {
 if (promptDirection("Which way?") == "L") {
 return "a house";
 } else {
 return "two angry bears";
 }
}

try {
 console.log("You see", look());
} catch (error) {
 console.log("Something went wrong: " + error);
}

throw關鍵字用于引發異常。 異常的捕獲通過將一段代碼包裝在一個try塊中,后跟關鍵字catch來完成。 當try塊中的代碼引發異常時,將求值catch塊,并將括號中的名稱綁定到異常值。 在catch塊結束之后,或者try塊結束并且沒有問題時,程序在整個try / catch語句的下面繼續執行。

在本例中,我們使用Error構造器來創建異常值。這是一個標準的 JavaScript 構造器,用于創建一個對象,包含message屬性。在多數 JavaScript 環境中,構造器實例也會收集異常創建時的調用棧信息,即堆棧跟蹤信息(Stack Trace)。該信息存儲在stack屬性中,對于調用問題有很大的幫助,我們可以從堆棧跟蹤信息中得知問題發生的精確位置,即問題具體出現在哪個函數中,以及執行失敗為止調用的其他函數鏈。

需要注意的是現在look函數可以完全忽略promptDirection出錯的可能性。這就是使用異常的優勢:只有在錯誤觸發且必須處理的位置才需要錯誤處理代碼。其間的函數可以忽略異常處理。

嗯,我們要講解的理論知識差不多就這些了。

異常后清理

異常的效果是另一種控制流。 每個可能導致異常的操作(幾乎每個函數調用和屬性訪問)都可能導致控制流突然離開你的代碼。

這意味著當代碼有幾個副作用時,即使它的“常規”控制流看起來像它們總是會發生,但異常可能會阻止其中一些發生。

這是一些非常糟糕的銀行代碼。

const accounts = {
 a: 100,
 b: 0,
 c: 20
};

function getAccount() {
 let accountName = prompt("Enter an account name");
 if (!accounts.hasOwnProperty(accountName)) {
 throw new Error(`No such account: ${accountName}`);
 }
 return accountName;
}

function transfer(from, amount) {
 if (accounts[from] < amount) return;
 accounts[from] -= amount;
 accounts[getAccount()] += amount;
}

transfer函數將一筆錢從一個給定的賬戶轉移到另一個賬戶,在此過程中詢問另一個賬戶的名稱。 如果給定一個無效的帳戶名稱,getAccount將引發異常。

但是transfer首先從帳戶中刪除資金,之后調用getAccount,之后將其添加到另一個帳戶。 如果它在那個時候由異常中斷,它就會讓錢消失。

這段代碼本來可以更智能一些,例如在開始轉移資金之前調用getAccount。 但這樣的問題往往以更微妙的方式出現。 即使是那些看起來不像是會拋出異常的函數,在特殊情況下,或者當他們包含程序員的錯誤時,也可能會這樣。

解決這個問題的一個方法是使用更少的副作用。 同樣,計算新值而不是改變現有數據的編程風格有所幫助。 如果一段代碼在創建新值時停止運行,沒有人會看到這個完成一半的值,并且沒有問題。

但這并不總是實際的。 所以try語句具有另一個特性。 他們可能會跟著一個finally塊,而不是catch塊,也不是在它后面。 finally塊會說“不管發生什么事,在嘗試運行try塊中的代碼后,一定會運行這個代碼。”

function transfer(from, amount) {
 if (accounts[from] < amount) return;
 let progress = 0;
 try {
 accounts[from] -= amount;
 progress = 1;
 accounts[getAccount()] += amount;
 progress = 2;
 } finally {
 if (progress == 1) {
  accounts[from] += amount;
 }
 }
}

這個版本的函數跟蹤其進度,如果它在離開時注意到,它中止在創建不一致的程序狀態的位置,則修復它造成的損害。

請注意,即使finally代碼在異常退出try塊時運行,它也不會影響異常。finally塊運行后,堆棧繼續展開。

即使異常出現在意外的地方,編寫可靠運行的程序也非常困難。 很多人根本就不關心,而且由于異常通常針對異常情況而保留,因此問題可能很少發生,甚至從未被發現。 這是一件好事還是一件糟糕的事情,取決于軟件執行失敗時會造成多大的損害。

選擇性捕獲

當程序出現異常且異常未被捕獲時,異常就會直接回退到棧頂,并由 JavaScript 環境來處理。其處理方式會根據環境的不同而不同。在瀏覽器中,錯誤描述通常會寫入 JavaScript 控制臺中(可以使用瀏覽器工具或開發者菜單來訪問控制臺)。我們將在第 20 章中討論的,無瀏覽器的 JavaScript 環境 Node.js 對數據損壞更加謹慎。 當發生未處理的異常時,它會中止整個過程。

對于程序員的錯誤,讓錯誤通行通常是最好的。 未處理的異常是表示糟糕的程序的合理方式,而在現代瀏覽器上,JavaScript 控制臺為你提供了一些信息,有關在發生問題時堆棧上調用了哪些函數的。

對于在日常使用中發生的預期問題,因未處理的異常而崩潰是一種糟糕的策略。

語言的非法使用方式,比如引用一個不存在的綁定,在null中查詢屬性,或調用的對象不是函數最終都會引發異常。你可以像自己的異常一樣捕獲這些異常。

進入catch語句塊時,我們只知道try體中引發了異常,但不知道引發了哪一類或哪一個異常。

JavaScript(很明顯的疏漏)并未對選擇性捕獲異常提供良好的支持,要不捕獲所有異常,要不什么都不捕獲。這讓你很容易假設,你得到的異常就是你在寫catch時所考慮的異常。

但它也可能不是。 可能會違反其他假設,或者你可能引入了導致異常的 bug。 這是一個例子,它嘗試持續調用promptDirection,直到它得到一個有效的答案:

for (;;) {
 try {
 let dir = promtDirection("Where?"); // ← typo!
 console.log("You chose ", dir);
 break;
 } catch (e) {
 console.log("Not a valid direction. Try again.");
 }
}

我們可以使用for (;;)循環體來創建一個無限循環,其自身永遠不會停止運行。我們在用戶給出有效的方向之后會跳出循環。但我們拼寫錯了promptDirection,因此會引發一個“未定義值”錯誤。由于catch塊完全忽略了異常值,假定其知道問題所在,錯將綁定錯誤信息當成錯誤輸入。這樣不僅會引發無限循環,而且會掩蓋掉真正的錯誤消息——綁定名拼寫錯誤。

一般而言,只有將拋出的異常重定位到其他地方進行處理時,我們才會捕獲所有異常。比如說通過網絡傳輸通知其他系統當前應用程序的崩潰信息。即便如此,我們也要注意編寫的代碼是否會將錯誤信息掩蓋起來。

因此,我們轉而會去捕獲那些特殊類型的異常。我們可以在catch代碼塊中判斷捕獲到的異常是否就是我們期望處理的異常,如果不是則將其重新拋出。那么我們該如何辨別拋出異常的類型呢?

我們可以將它的message屬性與我們所期望的錯誤信息進行比較。 但是,這是一種不穩定的編寫代碼的方式 - 我們將使用供人類使用的信息來做出程序化決策。 只要有人更改(或翻譯)該消息,代碼就會停止工作。

我們不如定義一個新的錯誤類型,并使用instanceof來識別異常。

class InputError extends Error {}

function promptDirection(question) {
 let result = prompt(question);
 if (result.toLowerCase() == "left") return "L";
 if (result.toLowerCase() == "right") return "R";
 throw new InputError("Invalid direction: " + result);
}

新的錯誤類擴展了Error。 它沒有定義它自己的構造器,這意味著它繼承了Error構造器,它需要一個字符串消息作為參數。 事實上,它根本沒有定義任何東西 - 這個類是空的。 InputError對象的行為與Error對象相似,只是它們的類不同,我們可以通過類來識別它們。

現在循環可以更仔細地捕捉它們。

for (;;) {
 try {
 let dir = promptDirection("Where?");
 console.log("You chose ", dir);
 break;
 } catch (e) {
 if (e instanceof InputError) {
  console.log("Not a valid direction. Try again.");
 } else {
  throw e;
 }
 }
}

這里的catch代碼只會捕獲InputError類型的異常,而其他類型的異常則不會在這里進行處理。如果又輸入了不正確的值,那么系統會向用戶準確報告錯誤——“綁定未定義”。

斷言

斷言(assertions)是程序內部的檢查,用于驗證某個東西是它應該是的方式。 它們并不是用于處理正常操作中可能出現的情況,而是發現程序員的錯誤。

例如,如果firstElement被描述為一個函數,永遠不會在空數組上調用,我們可以這樣寫:

function firstElement(array) {
 if (array.length == 0) {
 throw new Error("firstElement called with []");
 }
 return array[0];
}

現在,它不會默默地返回未定義值(當你讀取一個不存在的數組屬性的時候),而是在你濫用它時立即干掉你的程序。 這使得這種錯誤不太可能被忽視,并且當它們發生時更容易找到它們的原因。

我不建議嘗試為每種可能的不良輸入編寫斷言。 這將是很多工作,并會產生非常雜亂的代碼。 你會希望為很容易犯(或者你發現自己做過)的錯誤保留他們。

本章小結

錯誤和無效的輸入十分常見。編程的一個重要部分是發現,診斷和修復錯誤。 如果你擁有自動化測試套件或向程序添加斷言,則問題會變得更容易被注意。

我們常常需要使用優雅的方式來處理程序可控范圍外的問題。如果問題可以就地解決,那么返回一個特殊的值來跟蹤錯誤就是一個不錯的解決方案。或者,異常也可能是可行的。

拋出異常會引發堆棧展開,直到遇到下一個封閉的try/catch塊,或堆棧底部為止。catch塊捕獲異常后,會將異常值賦予catch塊,catch塊中應該驗證異常是否是實際希望處理的異常,然后進行處理。為了有助于解決由于異常引起的不可預測的執行流,可以使用finally塊來確保執行try塊之后的代碼。

習題

重試

假設有一個函數primitiveMultiply,在 20% 的情況下將兩個數相乘,在另外 80% 的情況下會觸發MultiplicatorUnitFailure類型的異常。編寫一個函數,調用這個容易出錯的函數,不斷嘗試直到調用成功并返回結果為止。

確保只處理你期望的異常。

class MultiplicatorUnitFailure extends Error {}

function primitiveMultiply(a, b) {
 if (Math.random() < 0.2) {
 return a * b;
 } else {
 throw new MultiplicatorUnitFailure();
 }
}

function reliableMultiply(a, b) {
 // Your code here.
}

console.log(reliableMultiply(8, 8));
// → 64

上鎖的箱子

考慮以下這個編寫好的對象:

const box = {
 locked: true,
 unlock() { this.locked = false; },
 lock() { this.locked = true; },
 _content: [],
 get content() {
 if (this.locked) throw new Error("Locked!");
 return this._content;
 }
};

這是一個帶鎖的箱子。其中有一個數組,但只有在箱子被解鎖時,才可以訪問數組。不允許直接訪問_content屬性。

編寫一個名為withBoxUnlocked的函數,接受一個函數類型的參數,其作用是解鎖箱子,執行該函數,無論是正常返回還是拋出異常,在withBoxUnlocked函數返回前都必須鎖上箱子。

const box = {
 locked: true,
 unlock() { this.locked = false; },
 lock() { this.locked = true; },
 _content: [],
 get content() {
 if (this.locked) throw new Error("Locked!");
 return this._content;
 }
};

function withBoxUnlocked(body) {
 // Your code here.
}

withBoxUnlocked(function() {
 box.content.push("gold piece");
});

try {
 withBoxUnlocked(function() {
 throw new Error("Pirates on the horizon! Abort!");
 });
} catch (e) {
 console.log("Error raised:", e);
}
console.log(box.locked);
// → true

以上是“JavaScript中BUG和錯誤怎么辦”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

岑巩县| 舟曲县| 锦屏县| 峨眉山市| 贵港市| 黎平县| 凉山| 沂水县| 金阳县| 肇源县| 双桥区| 习水县| 灵台县| 朝阳市| 龙江县| 建德市| 宜阳县| 竹溪县| 六安市| 福鼎市| 遂川县| 宁武县| 油尖旺区| 金川县| 镇坪县| 平远县| 新野县| 龙口市| 青龙| 通山县| 汽车| 定陶县| 隆子县| 淮安市| 澄江县| 长春市| 信阳市| 丘北县| 英超| 金山区| 武穴市|