宣告:前面是需求的來源和詳解,想看最后效果的可以直接翻到最后面
- 為什么會需要獲取代碼的行號?
- 如何獲取代碼的行號?
- 最終效果
為什么會需要獲取代碼的行號?
在我們開發專案的程序中,有些地方可能理論上是沒有問題的,但是為了以防萬一,還是加了一個判斷用來預防,
例如:
function f1() {
return parseInt(Math.random() * 2 + 1);
}
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
console.log('出bug了');
}
}
f2();
上述代碼中,f1函式在一些情況下會回傳數字1一些情況下會回傳或數字2(當然上面的代碼就只是用一個亂數模擬一下這個情景),f2函式知道f1函式只會回傳1或者2,于是用if-else判斷f1函式回傳的是1還是2,并做一些處理,如果二者都不是,則列印一下出bug了,這樣在除錯的時候我們看到了控制臺列印了’出bug了’之后就會知道這里出了問題,
現在假設我們在后來某一次改bug或者加需求的時候改了一下f1函式:
function f1() {
return parseInt(Math.random() * 3 + 1);
}
現在f1函式的回傳值就不止是1或2了,也就是f1函式被我們改的邏輯錯了,但是我們并沒有意識到,于是我們在除錯的時候,偶然的發現控制臺里列印了’出bug了’

而且還貼心的的告訴了我們這個’出bug了’是哪行代碼列印的,然后看了那行代碼之后,我們就知道我們在之前某次的改動中把f1函式給改出bug了,于是我們就會去修復這個bug,
但是上面這種情況是我們運氣好看到了控制臺列印了這個,如果我們除錯的時候沒在看控制臺,而是在觀察其它的東西(比如在看Network或者是頁面中的變化啥的),這樣的話我們可能就不能第一時間知道這個地方出bug了,而是好久之后才發現,這樣就會降低我們除錯的效率,
所以我們為了能夠第一時間知道哪里有bug,可以把console.log換成alert,
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('出bug了');
}
}
這樣如果f1函式出現了問題的話,會直接在頁面上彈一下,比較的顯眼,就可以第一時間發現問題從而去解決問題,

這樣我們就可以第一時間發現問題了,于是我們會去代碼里找是哪行代碼alert的這個,從而去修復這個bug
但是新的問題出現了,如果這種不確定的bug比較多的話
function f1() {
return parseInt(Math.random() * 3 + 1);
}
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('出bug了');
}
}
f2();
function f3() {
return parseInt(Math.random() * 3 + 1);
}
function f4() {
let x = f3();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('出bug了');
}
}
f4();
function f5() {
return parseInt(Math.random() * 3 + 1);
}
function f6() {
let x = f5();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('出bug了');
}
}
f6();
這樣當頁面alert出bug了之后我們就不知道到底是哪里的代碼alert的了
于是我們可能這樣做
function f1() {
return parseInt(Math.random() * 3 + 1);
}
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第12行代碼處出bug了');
}
}
f2();
function f3() {
return parseInt(Math.random() * 3 + 1);
}
function f4() {
let x = f3();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第27行代碼處出bug了');
}
}
f4();
function f5() {
return parseInt(Math.random() * 3 + 1);
}
function f6() {
let x = f5();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第42行代碼處出bug了');
}
}
f6();
這樣再alert的時候我們就知道是哪行alert的了
不過這樣還是有一個問題,如果我們在這寫代碼上面的代碼做了一些修改的話
function f1() {
return parseInt(Math.random() * 3 + 1);
}
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第12行代碼處出bug了');
}
}
f2();
// 這里加了一點代碼 --------------
let a = 1;
// ----------------
function f3() {
return parseInt(Math.random() * 3 + 1);
}
function f4() {
let x = f3();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第27行代碼處出bug了');
}
}
f4();
// 這里加了億點代碼 --------------
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
console.log(sum);
const html = document.documentElement;
const body = html.children[1];
body.style.backgroundColor = 'pink';
let div = document.createElement('div');
div.innerText = 'hello bug';
body.appendChild(div);
// ----------------
function f5() {
return parseInt(Math.random() * 3 + 1);
}
function f6() {
let x = f5();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第42行代碼處出bug了');
}
}
f6();
這些alert陳述句所在的行數就會發生改變,如果改動的不多的話還好,最后也會在附近

但是改動比較多的話就不太好找了,這樣就不利于我們去找bug

既然這樣,那么為了防止alert竄行,我們可以在程式里先獲取一下當前alert代碼所在的行號,然后再alert出來
于是我去在網上搜了一波,但是也沒搜到js能獲取行號的內置函式
既然沒有自帶的,那我們就自己寫一個吧哈哈哈
function getRow() {
return // 當前行數
}
假設我們如果寫好了一個這樣功能的函式,那么之前的代碼就可以改成這樣,就可以解決我們的問題了:
function f1() {
return parseInt(Math.random() * 3 + 1);
}
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第1' + getRow() + '行代碼處出bug了');
}
}
f2();
// 這里加了一點代碼 --------------
let a = 1;
// ----------------
function f3() {
return parseInt(Math.random() * 3 + 1);
}
function f4() {
let x = f3();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第' + getRow() + '行代碼處出bug了');
}
}
f4();
// 這里加了億點代碼 --------------
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
console.log(sum);
const html = document.documentElement;
const body = html.children[1];
body.style.backgroundColor = 'pink';
let div = document.createElement('div');
div.innerText = 'hello bug';
body.appendChild(div);
// ----------------
function f5() {
return parseInt(Math.random() * 3 + 1);
}
function f6() {
let x = f5();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第' + getRow() + '行代碼處出bug了');
}
}
f6();
那么本文的核心來了,要如何獲取行號呢
如何獲取代碼的行號?
首先,先來回憶一下,我們都在什么地方見到過代碼行號
首先,上文中提到的console.log()在將內容列印到控制臺的時候,在右側會顯示是哪行列印的,這里就出現了一個行號,但是console.log()這個東西它的內部比較高深,目前已咱這個水平也研究不明白
那么就需要再想想哪里還出現過行號
還記不記得,每次當代碼報錯的時候,都會顯示是哪行代碼報的錯,這里也出現了行號!
throw new Error('錯誤原因');

既然這個例外物件里面有報錯的代碼的行數,那我們就好好研究一下這個Error吧
console.log(new Error('錯誤原因'));
如果我們直接將這個例外物件列印出來的話,是這樣的

既然這樣,我們就可以分割一下字串,從而獲取到這個行號1,記得要先轉化成字串,這里我是通過冒號分割的
console.log((new Error('錯誤原因') + '').split(':'));

emmm看樣子好像不太行,例外物件轉化成字串之后和在console.log里列印的東西不太一樣,可能是以為內部有什么轉換機制吧,不太清楚
那么……就要另尋他路
我們先用瀏覽器看看例外物件里都有啥吧

emmm根據觀察
首先constructor是建構式,應該沒啥用
然后message應該是例外的資訊,就是我們new的時候傳進去的那個
name應該是這個例外的型別的名字,也用處不大
toString()就不用說了,剛剛上面轉化成字串的時候內部呼叫的就是這個函式
那么就剩一個stack了
那么我們看看這是啥
console.log(new Error().stack);
console.log(typeof new Error().stack);

很好,這里面有行號,而且它還是個字串,這不就正是我們需要的東西嗎
那么我們就來利用一下它
let e = new Error();
console.log(e.stack);
console.log(e.stack.split(':'));

那么陣列里索引為3的元素就是我們要的行號1了
把它取出來
let e = new Error();
// console.log(e.stack);
console.log(e.stack.split(':')[3]);

那么我們只要在getRow函式中回傳這個就可以了
function getRow() {
let e = new Error();
// console.log(e.stack);
return e.stack.split(':')[3];
}
console.log(getRow());

好像不太對,我們需要的應該是呼叫getRow函式的那一行的行號也就是6,但是回傳的是創建例外物件的行號2
不難發現,例外物件中還會記錄函式的呼叫的行號
那么我們再做個實驗
function getRow() {
let e = new Error();
console.log(e.stack);
console.log(e.stack.split(':'));
// return e.stack.split(':')[3];
}
function f1() {
console.log(getRow());
}
function f2() {
f1();
}
function f3() {
f2();
}
f3();
f2();
console.log(getRow());

例外物件會把層層呼叫的函式的行號都記錄下來,我們需要的是呼叫getRow函式的行號,也就是第二層的呼叫,也就是分割后的陣列的索引為7的那個元素
function getRow() {
let e = new Error();
return e.stack.split(':')[7];
}
function f1() {
console.log(getRow());
}
function f2() {
f1();
}
function f3() {
f2();
}
f3();
console.log(getRow());

現在我們的getRow函式就可以成功且準確的獲取到代碼的行號了!!!
考慮到以后或許可能還會用需要用這個行號計算(雖然這個幾乎不可能,應該不會用需要用行號計算的需求吧,我覺得我這個獲取行號的需求已經挺奇葩的了哈哈哈),所以回傳的時候也可以轉化成數值型
最終效果
那么最終的效果就是這樣啦:
/**
* 函式功能:獲取代碼行號
*
* @returns 回傳函式呼叫處的代碼行號
* @author 60rzvvbj
*/
function getRow() {
return parseInt(new Error().stack.split(':')[7]);
}
// 用之前的代碼測驗一下
function f1() {
return parseInt(Math.random() * 3 + 1);
}
function f2() {
let x = f1();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第' + getRow() + '行代碼處出bug了');
}
}
f2();
// 這里加了一點代碼 --------------
let a = 1;
// ----------------
function f3() {
return parseInt(Math.random() * 3 + 1);
}
function f4() {
let x = f3();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第' + getRow() + '行代碼處出bug了');
}
}
f4();
// 這里加了億點代碼 --------------
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
console.log(sum);
const html = document.documentElement;
const body = html.children[1];
body.style.backgroundColor = 'pink';
let div = document.createElement('div');
div.innerText = 'hello bug';
body.appendChild(div);
// ----------------
function f5() {
return parseInt(Math.random() * 3 + 1);
}
function f6() {
let x = f5();
if (x == 1) {
// 如果是1,則進行一些操作
} else if (x == 2) {
// 如果是2,則進行一些操作
} else {
// 如果既不是1也不是2,則說明f1函式的邏輯出現了錯誤
alert('第' + getRow() + '行代碼處出bug了');
}
}
f6();
運行結果:

很好,完全正確!!!
如果覺得這個沒啥用就當看個樂子吧,不喜勿噴哦
ヾ(≧∪≦*)ノ〃
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/258973.html
標籤:其他
下一篇:前端MUI+H5+HBuilderX開發APP(IOS,android),后臺Springboot,首頁,圖片輪播等,更新中(三 )
