青训营月影老师告诉我写好JavaScript的四大技巧——风格优先

Posted YK菌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了青训营月影老师告诉我写好JavaScript的四大技巧——风格优先相关的知识,希望对你有一定的参考价值。

如何写好javascript肯定是每一个前端工程师一直以来要思考的问题,月影老师告诉我们一些写好JavaScript的原则,同时也教了一些我们如何写好JavaScript的技巧,今天来继续跟着月影老师学JavaScript吧~~

我们在写代码的时候,最应该关注的什么?

程序是写给人读的,只是偶尔让计算机执行一下。 —— Donald Ervin Knuth(高德纳)

编码风格当然是写好代码最应该关注的,其次才是编码效率。(这也不是一定的~还是要根据使用场景来判断)

Left-pad事件

回顾一下2016年引起热议的Left-pad事件


图片来自大圣2016年的博客

事件本身有很多槽点

  • NPM 模块粒度
  • 代码风格
  • 代码质量/效率
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模块粒度的问题,为什么一个函数就构成了一个模块,粒度是不是太细了,其实当年的打包工具什么的还没有那么强大的tree shaking功能,所以粒度不得不弄这么小。现在来说是粒度太细了,但是在当年来说是无可厚非的。

代码风格问题,这个代码写的可读性很高,很简单的代码。好的代码本身即注释

最后是代码效率,这里确实效率不高,是O(N)的时间复杂度,但是结合实际,我们实际用的时候也不会用到前面拼很多很多的字符的情况,所以这样也是可以的。

综上所述,这段代码没啥问题~

我们来看看为何那么多人吐槽它的效率低,怎么改进能提升这段代码的效率呢?

我们就看循环部分,让你重复一个字符串n次,真的需要n次循环来一步一步的拼串吗?

while(++i < len){
    str = ch + str;
}

比如要将 * 重复 100 遍

100 的 二进制是 1100100

while循环相当于是用十进制的思想,连续拼加了100次的*(感觉这里应该说是数数的思想)

而使用二进制的思想,每次*都翻倍(2的幂),只需要循环7次就可以完成,我们看下面的代码来理解

这是优化的代码

function leftpad(str, len, ch=""){
    str = "" + str;

    const padLen = len - str.length;
    
    if(padLen <= 0){
        return str;
    }else{
        return ("" + ch).repeat(padLen) + str;
    }
}

这里用到了ES6的一些特性,默认赋值,字符串的repeat方法,重点是它怎么实现重复n次操作的

它在MDN上给出的ployfill实现中关键代码是这样的定义的

var rpt = ""
for(;;){
    if((count & 1) == 1) {
        rpt += str;
    }
    
    count >>>= 1;
    
    if(count == 0){
        break;
    }
    
    str += str;
}

我们来解读一下这段代码。这里用到了位运算: &与运算 与 >>>无符号右移运算

count & 1 取count二进制的最低位,判断和1是否相同,相同返回1,否则返回0

count >>> 1 把count的二进制右移一位,即去掉其二进制位的最低位

所以这段代码的意思就是逆序遍历 count 的二进制形式,str每次都翻倍,遇到二进制位是1的就将str拼到rpt中去

还是上面说的重复100次 * 的例子
倒着遍历100的二进制1100100,每次都对str进行翻倍操作,二进制中遇到1的时候就让rpt加上当前的str

这里会循环7+1次, str 分别是 1*(0)、 2*(0)、4*(1)、8*(0)、16*(0)、32*(1)、64*(1),所以最后rpt就是 4+32+64=100个 *

所以这里的时间复杂度是 O(logN) 循环的次数 是 count的二进制的位数

其实还是可以继续优化的

var rpt = "";
do {
    rpt += str;
    str += str;
    count &= count - 1;
} while(count);

count &= count - 1; 可以去掉二进制中最后面的1

1100100 -> 1100000 -> 1000000 -> 0000000

这里循环的次数 是 count的二进制数中1的位数
比如100的二进制是 1100100,就会循环 3 次

但是这种情况达不到我们要的结果,应该是老师PPT弄错了~或者是我理解错了,如果知道什么情况的,可以留言或者私信教教我

然而有意思的是,现在 MDN 给出的ployfill代码已经更改成使用while循环这样的代码了😂😂😂

while (count) {
   str += str;
   count--;
}

搞了半天效率又回去了~~ 哈哈

也就是说在大部分场景下,对效率的要求没有那么恐怖,所以注重代码风格优先仍然是写好JavaScript代码的一个重要技巧!

判断单位矩阵

我们看下面这段代码

这段代码对我看来,是有很多问题的

  1. 太长了,可读性一般
  2. 拓展性不高
  3. 封装性不好

但是,这是一段真实的代码

因为这是当前条件下,效率最高的方式,而这个场景是需要效率优先的。

所以说在实际开发中,我们还是要视具体情况而定的。

总结

这里我们学到了使用位运算来提高我们的代码效率

但是实际上,我们更应该关注我们代码的可读性

当然这都需要根据实际场合进行取舍

以上是关于青训营月影老师告诉我写好JavaScript的四大技巧——风格优先的主要内容,如果未能解决你的问题,请参考以下文章

青训营月影老师告诉我写好JavaScript的四大技巧——风格优先

青训营月影老师告诉我写好JavaScript的四大技巧——风格优先

青训营月影老师告诉我写好JavaScript的四大技巧——妙用特性

青训营月影老师告诉我写好JavaScript的三大原则之——过程抽象

青训营月影老师告诉我写好JavaScript原则与技巧大总结

青训营月影老师告诉我写好JavaScript原则与技巧大总结