js获取当前代码行号

声明:前面是需求的来源和详解,想看最后效果的可以直接翻到最后面

  • 为什么会需要获取代码的行号?
  • 如何获取代码的行号?
  • 最终效果
为什么会需要获取代码的行号?

在我们开发项目的过程中,有些地方可能理论上是没有问题的,但是为了以防万一,还是加了一个判断用来预防。
例如:

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了’
1
而且还贴心的的告诉了我们这个’出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函数出现了问题的话,会直接在页面上弹一下,比较的显眼,就可以第一时间发现问题从而去解决问题。
js获取当前代码行号_第1张图片
这样我们就可以第一时间发现问题了,于是我们会去代码里找是哪行代码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语句所在的行数就会发生改变,如果改动的不多的话还好,最后也会在附近
js获取当前代码行号_第2张图片
但是改动比较多的话就不太好找了,这样就不利于我们去找bug
js获取当前代码行号_第3张图片
既然这样,那么为了防止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('错误原因');

js获取当前代码行号_第4张图片
既然这个异常对象里面有报错的代码的行数,那我们就好好研究一下这个Error

console.log(new Error('错误原因'));

如果我们直接将这个异常对象打印出来的话,是这样的
js获取当前代码行号_第5张图片
既然这样,我们就可以分割一下字符串,从而获取到这个行号1,记得要先转化成字符串,这里我是通过冒号分割的

console.log((new Error('错误原因') + '').split(':'));

js获取当前代码行号_第6张图片
emmm看样子好像不太行,异常对象转化成字符串之后和在console.log里打印的东西不太一样,可能是以为内部有什么转换机制吧,不太清楚
那么……就要另寻他路
我们先用浏览器看看异常对象里都有啥吧
js获取当前代码行号_第7张图片
emmm根据观察
首先constructor是构造函数,应该没啥用
然后message应该是异常的信息,就是我们new的时候传进去的那个
name应该是这个异常的类型的名字,也用处不大
toString()就不用说了,刚刚上面转化成字符串的时候内部调用的就是这个函数
那么就剩一个stack
那么我们看看这是啥

console.log(new Error().stack);
console.log(typeof new Error().stack);

js获取当前代码行号_第8张图片
很好,这里面有行号,而且它还是个字符串,这不就正是我们需要的东西吗
那么我们就来利用一下它

let e = new Error();
console.log(e.stack);
console.log(e.stack.split(':'));

js获取当前代码行号_第9张图片
那么数组里索引为3的元素就是我们要的行号1了
把它取出来

let e = new Error();
// console.log(e.stack);
console.log(e.stack.split(':')[3]);

js获取当前代码行号_第10张图片
那么我们只要在getRow函数中返回这个就可以了

function getRow() {
     
    let e = new Error();
    // console.log(e.stack);
    return e.stack.split(':')[3];
}
console.log(getRow());

js获取当前代码行号_第11张图片
好像不太对,我们需要的应该是调用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());

js获取当前代码行号_第12张图片
异常对象会把层层调用的函数的行号都记录下来,我们需要的是调用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());

14
现在我们的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();

运行结果:
js获取当前代码行号_第13张图片
很好,完全正确!!!

如果觉得这个没啥用就当看个乐子吧,不喜勿喷哦


ヾ(≧∪≦*)ノ〃

你可能感兴趣的:(前端,js,javascript)