前言
如何写好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; 复制代码
这跟最开始没有改进时一样,所以说大部分场景不需要注重效率,代码风格才是我们最应该注意的。