除了以上介绍的四点建议外 , 还有很多可以改善阅读体验的点 , 如:有效的注释、避免不同类型的比较、避免生涩的语法等等 。
高性能的代码在软件开发中 , 代码的性能高低会直接影响到产品的用户体验 , 所以高质量的代码必然是高性能的 。这里总结了四点具体操作方式分享给大家 。
提示:测试JavaScript平均耗时 , 可使用console.time()方法、JSBench.Me工具、performance工具等 。
第一点:优化算法递归是一种常见的算法 , 下面是用递归实现的“求阶乘”的操作 。
// badfunction foo(n) {if (n === 1) {return 1}return n * foo(n - 1)}foo(100)// 平均耗时:0.47ms// goodfunction foo(n, result = 1) {if (n === 1) {return result}return foo(n - 1, n * result)// 这里尾调用优化}foo(100)// 平均耗时:0.09ms“尾调用”是一种可以重用栈帧的内存管理优化机制 , 即外部函数的返回值是一个内部函数的返回值 。
第二点:使用内置方法很多功能都可以采用JavaScript内置方法来解决 , 往往内置方法的底层实现是最优的 , 并且内置方法可在解释器中提前执行 , 所以执行效率非常高 。
下面举例为:获取对象属性和值的复合数组形式 。
// badlet data = https://www.isolves.com/it/cxkf/yy/js/2022-10-11/{username: "leo",age: 20,gender: "male",}let result = []for (let attr in data) {result.push([attr, data[attr]])}console.log(result)// goodlet data = {username: "leo",age: 20,gender: "male",}let result = Object.entries(data)console.log(result)第三点:减少作用域链查找作用域链是作用域规则的实现 , 通过作用域链的实现 , 变量在它的作用域内可被访问 , 函数在它的作用域内可被调用 。作用域链是一个只能单向访问的链表 , 这个链表上的每个节点就是执行上下文的变量对象(代码执行时就是活动对象) , 单向链表的头部(可被第一个访问的节点)始终都是当前正在被调用执行的函数的变量对象(活动对象) , 尾部始终是全局活动对象 。
概念太复杂的话 , 看下面这样一张图 。

文章插图
作用域链这个链表就是 3(头部:bar) -> 2(foo) -> 1(尾部:全局) , 所以查找变量的时候 , 应尽量在头部完成获取 , 这样就可以节省性能 , 具体对比如下 。
// badfunction foo() {$("li").click(function () {// 全局查找一次$("li").hide()// 再次全局查找一次$(this).show()})}// goodfunction foo() {let $li = $("li")// 减少下面$li的作用域查找层级$li.click(function () {$li.hide()$(this).show()})}除了减少作用域链查找外 , 减少对象属性的查找也是一样的道理 。【3个编写JavaScript高质量代码的技巧,让你不再996】
// badfunction isNull(arg) {return Object.prototype.toString.call(arg) === "[object Null]"}function isFunction(arg) {return Object.prototype.toString.call(arg) === "[object Function]"}// goodlet toString = Object.prototype.toStringfunction isNull(arg) {return toString.call(arg) === "[object Null]"}function isFunction(arg) {return toString.call(arg) === "[object Function]"}第四点:避免做重复的代码有时候编写程序时 , 会出现很多重复执行的代码 , 最好要避免做重复操作 。先举一个简单的例子 , 通过循环找到第一个满足条件元素的索引位置 。// badlet index = 0for (let i = 0, len = li.length; i < len; i++) {if (li[i].dataset.switch === "on") {index = i}}// goodlet index = 0for (let i = 0, len = li.length; i < len; i++) {if (li[i].dataset.switch === "on") {index = ibreak// 后面的循环没有意义 , 属于执行不必要的代码}}再来看一个计算“斐波那契数列”的案例 。// badfunction foo(n) {if (n < 3) {return 1}return foo(n - 1) + foo(n - 2)}foo(40)// 平均耗时:1043ms// goodlet cache = {}function foo(n) {if (n < 3) {return 1}if (!cache[n]) {cache[n] = foo(n - 1) + foo(n - 2)}return cache[n]}foo(40)// 平均耗时:0.16ms这里把递归执行过的结果缓存到数组中 , 这样接下来重复的代码就可以直接读取缓存中的数据了 , 从而大幅度提升性能 。
文章插图
画叉号的部分就会走缓存 , 而不会重复执行计算 。
推荐阅读
- 衬衫|DNF:110版本还未加强的14个职业!3个已无望,2个重做可能性高
- 招聘|这3个岗位往届生也可以报考,不仅有五险一金,还有编制
- 罗云熙|老福特言情CP浏览量榜单,罗云熙前6有3个,看到第一满意离开!
- 李晨|打破3个影史纪录,9次荣登票房日冠军,李晨的眼光真精准
- 招聘|殡仪馆也是“铁饭碗”,转正有五险一金,这3个条件需满足!
- 妇科疾病该怎么治疗?躲过3个误区 妇科疾病治疗
- 漫画 男人身体的13个小秘密
- 天气转冷后,电动车电池变得不耐用,这3个方法解决跑不远的问题
- 老人死去的前兆,老人过世的前兆-
- 江玉燕|电视剧中常演“坏女人”的3个人,尽管心狠手辣,却因为她们的美丽而被人怜惜
