这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战。
嗟予贫贱年将老,学古忧时满怀抱。
前言
如何写好JS,什么才叫好的代码?这是个很难回答的问题,一千个人中有一千个哈姆雷特,本文只是浅显地讨论一下写代码最应该关注什么?
先来看一段代码:
//判断一个mat2d矩阵是否是单位矩阵
function isUnitMatrix2d(m) {
return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0;
}
单从代码优雅性来说,这个代码看着就挺low的,但它是4.8k⭐的开源项目spritejs里的真实代码,这段代码是负责图形渲染的,也就是说每一帧的计算都要用到这段代码,在这样的场景下,我们最应该关注的是效率性能,而不是代码风格。
所以,一般来说,写代码要结合使用场景,关注以下几个方面:
当年的Left-pad事件
很多流行的npm模块因为引入了一个叫做left-pad的模块,导致无法正常运行,这个模块中只有11行代码,就是一个简单的字符串处理函数:
module.exports = leftpad;
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
这个事情本身的槽点很多,首先就是NPM模块粒度的问题,为什么一个函数11行代码就构成了一个模块,粒度是不是太细了?然后是代码风格问题,这个代码的可读性很高,但是代码效率很低,时间复杂度为O(N),总体而言,代码本身没什么大问题。
但是考虑到效率,还是可以对代码进行改进的,最影响效率的地方就是循环部分,我们并不需要一个一个的拼接,可以采用repeat()方法简化同时提升效率:
function leftpad(str, len, ch=""){
str = "" + str;
const padLen = len - str.length;
if (padLen <= 0){
return str;
} else {
return ("" + ch).repeat(padLen) + str;
}
}
以前的MDN文档中关于repeat()的核心代码是:
var rpt = "";
for(;;) {
if ((count & 1) == 1) {
rpt += str;
}
count >>>= 1;
if (count == 0){
break;
}
str += str;
}
就是通过位运算减少循环次数,比如传进来的数是20,它的二进制是0001 0100,每次比较最后一位,如果为1就拼接上,然后右移一位,重复这个过程即可,时间复杂度为O(log2N)。
但是现在MDN的repeat()中核心代码是:
var maxCount = str.length * count;
count = Math.floor(Math.log(count) / Math.log(2));
// while循环
while (count) {
str += str;
count--;
}
str += str.substring(0, maxCount - str.length);
return str;
这跟最开始没有改进时一样,所以说大部分场景不需要注重效率,代码风格才是我们最应该注意的。