前面已经分享了该如何写好JS的一些方式技巧,本篇就来做个最后的总结,看看写代码最应该关注什么?哪些写法是不可取,可以改进的。
前言
『前期回顾』
先从一段代码开始
以下的这段代码好不好?为什么?(可以先思考1秒🤔)
👇
👇
👇
👇
👇
👇
其实这是spriteJs 框架的一段真实的代码,可以翻到131行看一下
spriteJs 是一款由 360 奇舞团开源的跨终端 canvas 绘图框架,可以基于 canvas 快速绘制结构化 UI、动画和交互效果,是跨平台的2D绘图对象模型库,它能够支持web、node、桌面应用和微信小程序的图形绘制和实现各种动画效果。
如果从优雅性来说,这段代码看上去并不够简洁,但是为什么要这么写呢?
首先这是一个图形库,这段代码主要是负责,在渲染之前计算我们图层transform矩阵的逻辑代码,也就是说在每一帧的渲染之前都要去计算。
在这种情况下,任何一种其他写法的性能都不如这样直接展开写的好。这样展开来写,就不需要用任何的循环或其他的逻辑,只需要从索引中直接取出内容来比较,这样性能是最高的。
但是在一般的代码中,对性能没有这么敏感的话,是不需要这样写的,可以用其他的一些写法,来让我们的代码短一点。
为什么要说这个案例?
我们的所有代码风格都应该是根据场合来的,如果你在一些框架或库中看到一些比较死板,不是那么优雅的写法,那就应该要结合该框架或库来看,这样设计或许都是有理由的。
写代码最应该关注什么?
我们应该考虑以下几点
- 风格(同一套代码应该要统一)
- 效率(写代码的时候应该多考虑代码的效率,尽量写效率高的代码)
- 约定
- 使用场景(也需要结合场景,也的时候也不应该为了追求极致的效率,而牺牲代码的可读性)
- 设计
当年的Left-pad事件
leftpad就是一个简单的字符串处理函数
- 当字符串的长度没有达到我们要的长度时,就在它的左边补若干个字符,把它的长度补齐
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模块粒度
-
代码风格
-
代码质量/效率
优化上面的代码
- 代码更简洁
- 效率提升
关于repeat👉Repeat polyfill / MDN
一些关键词
- 时间复杂度
- 快速幂
一段瞎科普:【Left-pad事件】就是当年 NPM 圈发生的“一个十几行代码的模块引发的血案”。left-pad工具模块被作者 Azer从 NPM 上撤下,所有直接或者间接依赖这个模块的 NPM 包就都忧伤的挂掉了,其中就包括 babel 、React等。
再插一段小八卦:作者为什么要删包?事情是这样的,Azer 写了一个工具叫 kik 发布在 npm 上,这天有个同名的公司律师找上门要求他删掉,Azer 不从,这律师就找上 npm,npm 把包的管理权限转给了这家公司——当然,Azer 就怒了,从 npm 上解放了所有自己发布的包。就是酱😖
交通灯状态切换
来实现一个切换多个交通灯状态切换的功能
版本一
没有封装、不可扩展,不美观(不及格)
怎么去优化?
首先应该要对数据做一个封装,数据封装之前应该先对数据进行抽象,抽象以后把一些信息给隐藏起来
我们要实现的交通灯,本质是
- 我们要接收一组状态
- 然后根据这组状态来进行某些指令(如改变元素class)
- 然后去做状态切换
版本二
数据做了封装,状态切换操作也做了封装
关键词
- 数据抽象
版本三
上面做的是数据抽象,在上一篇中,我们有提到一个【过程抽象】的概念,我们也可以通过【过程抽象】来实现。
解析
- 切换状态本身它就是一个【轮询操作】,所以我们可以把前面的【start方法】抽象出一个【轮询方法】
- 【轮询方法】中传入一个【函数操作】列表
- 然后依次取出当前要操作的函数
- 然后执行这个函数
关键词
- 过程抽象
- 高阶函数
版本四
还可以利用async...await
来实现,首先交通灯拆解开来 主要就是两种操作
- 等待
- 状态切换
关键词
- 命令式写法
以上写法虽然各有优化,但是都还有可以改进的地方
判断是否是4的幂
4的0次方 = 1
4的1次方 = 4
4的2次方 = 16
....
4的4次方 = 64
....
版本一
中规中矩
关键词
- 幂
- 因式分解
- 时间复杂度
版本二
版本三
4的幂,则它转化为二进制之后
- 首页肯定是1
- 后面都是0
- 并且0的个数都是偶数
关键词
- 常数复杂度
- 按位与
版本四
function isPower0fFour(num){
num = parseInt(num).toString(2);//转成二进制的字符串
return /^1(?:00)*$/.test(num);//用正则表达式匹配一下
}
洗牌
正确性
如果按以下写法,是否正确?
可以测试一下,如果这个洗牌是公平的,那把如果洗10000000次,把得到的数组的每个对应位置的数字想加,得到的和应该是差不多的
但是通过结果可以看到,越前面的越小
改进一
改进二
const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function * draw(cards){
const c = [...cards];
for(let i = c.length; i > 0; i--) {
const pIdx = Math.floor(Math.random() * i);
[c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
yield c[i - 1];
}
}
const result = draw(cards);
console.log([...result]);
后面的几个案例出现了一些算法的概念,不过算法不是我们当前的主题,所以等以后在细说吧!
结语
本节课的讲师:字节前端/掘金开发负责人—月影
如以上有错误的地方,请在评论区中指出!
小可爱看完点个赞再走吧!😗