航天员|如何编写高质量 JavaScript 代码( 三 )


// badfunction foo() {  $(\"li\").click(function () {     // 全局查找一次    $(\"li\").hide()                // 再次全局查找一次    $(this).show()  )// goodfunction foo() {  let $li = $(\"li\")               // 减少下面$li的作用域查找层级        $li.click(function () {          $li.hide()                   $(this).show()  )

除了减少作用域链查找外 , 减少对象属性的查找也是一样的道理 。
// 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 = i        break        // 后面的循环没有意义 , 属于执行不必要的代码    

再来看一个计算“斐波那契数列”的案例 。
// 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

这里把递归执行过的结果缓存到数组中 , 这样接下来重复的代码就可以直接读取缓存中的数据了 , 从而大幅度提升性能 。


作者:子晨

画叉号的部分就会走缓存 , 而不会重复执行计算 。
除了以上介绍的四点建议外 , 还有很多可以改善代码性能的点 , 如:减少DOM操作、节流处理、事件委托等等 。
健壮性的代码
所谓健壮性的代码 , 就是编写出来的代码 , 是可扩展、可维护、可测试的代码 。 这里总结了四点具体操作方式分享给大家 。
第一点:使用新语法
很多新语法可弥补之前语法的BUG , 让代码更加健壮 , 应对未来 。
// badvar a = 1isNaN(NaN)              // trueisNaN(undefined)        // true// goodlet a = 1Number.isNaN(NaN)       // trueNumber.isNaN(undefined) // false

新语法还可以简化之前的操作 , 让代码结构更加清晰 。
// badlet user = { name: \"james\" age: 36 function foo() {  let arg = arguments  let name = user.name  let age = user.age// goodlet user = { name: \"james\" age: 36 function foo(...arg) {          // 剩余参数  let { name age= user      // 解构赋值

第二点:随时可扩展
由于产品需求总是会有新的变更 , 对软件的可扩展能力提出了很高要求 , 所以健壮的代码都是可以随时做出调整的代码 。
// badfunction foo(animal) {  if (animal === \"dog\" || animal === \"cat\") {    // todos  function bar(name age) {bar(\"james\" 36)// goodfunction foo(animal) {  const animals = [\"dog\" \"cat\" \"hamster\" \"turtle\"