js 代码优化

548 阅读1分钟

在日常书写js的过程中,我们要从每一行代码开始,去提升速度,优化性能。 我总结了日常代码的一些提升点,在代码大量执行的时候,注意这些,会在速度或性能上有所提升。

性能测试网站:

jsbench.me/

慎用全局变量

全局变量特点:

  • 全局变量定义在全局执行上下文,是作用域的顶端,层级查找时间消耗大

  • 全局上下文一直存在上下文执行栈,直到程序退出,不会被回收

  • 如果局部作用域中定义同名变量,会导致全局变量被遮蔽或污染

优化点:

  • 减少作用域链查找层级
// example1
let i
for (i = 0; i < 1000; i++) {
 console.log(i)
} 
// example2 -- fastest
for (let i = 0; i < 1000; i++) {
  console.log(i)
} 

缓存全局变量

  • 对于不可避免的全局变量,可以对全局变量进行缓存

优化点:

  • 减少了数据读取次数(但是消耗了空间)
// example1
function logInfo() {
  for (let i = 0; i < 1000; i++) {
   console.log(i)
  }
}
logInfo()
// example2 - fastest
function logInfo() {
  const log = console.log
  for (let i = 0; i < 1000; i++) {
   log(i)
  }
}
logInfo()

在原型对象上新增实例对象需要的方法

  • 原型对象中的方法是共享的,构造函数中的方法是单独存储的
// example1
let Fn1 = function () {
  this.foo = function() {
    console.log(1)
  }
}
let fn2 =  new Fn1() 

// example2 - fastest
let Fn2 = function () {}

Fn2.prototype.foo = function() {
  console.log(1)
}

let fn2 =  new Fn2()

避开闭包的陷阱

特点:

  • 外部具有指向内部的引用

  • 外部作用域访问内部作用域的变量

缺点:

  • 闭包使用不当容易出现内存泄漏

  • 不要为了闭包而闭包

优化点:

  • 合适的时候释放变量
 // example 1
 function foo () {
    let el = document.getElementById('btn')
    el.onclick = function() {
      console.log(el.id)
    }
  }
  // example 2 -  better
  function foo () {
    let el = document.getElementById('btn')
    el.onclick = function() {
      console.log(el.id)
    }
    // 释放空间
    el = null
  } 

避免属性访问方法的使用

  • JS不需要属性的访问方法,所以的属性都是外部可见的

  • 使用属性访问方法只会增加一重定义,没有访问的控制力

// example1
function Person () {
  this.name = 'jill'
  this.age = 18
  this.getAge = function () {
    return this.age
  }
}

const p1 = new Person()
const age = p1.getAge() 

// example2 - fastest
function Person () {
  this.name = 'jill'
  this.age = 18
}

const p1 = new Person()
const age = p1.age 

条件判断

1、对于明确条件分支可以用switch代替if-else

  • 条件较少时if-else更易读,但代码量较大时,switch看起来明朗一点

  • 大多数情况下switch要比if-else更快

2、确保最可能出现的条件放在首位

循环

优化for循环

1、缓存变量

<p class="btn">add</p>
<p class="btn">add</p>
<p class="btn">add</p>
<p class="btn">add</p>

// example1
const btns = document.getElementsByClassName('btn')

for (let i = 0; i < btns.length; i++) {
  console.log(i)
}
// example2 - fastest
const btns = document.getElementsByClassName('btn')

for (let i = 0, len = btns.length; i < len; i++) {
  console.log(i)
}

2、采用forEach循环方式

// example1- slower
const arr = [1, 3, 2, 4, 1]
for (let key in arr) {
  console.log(key)
}
// example2- better
const arr = [1, 3, 2, 4, 1]
for(let i = 0, len = arr.length; i < len; i++) {
  console.log(i)
} 
// example3- fastest
const arr = [1, 3, 2, 4, 1]
arr.forEach((item, index) => {
  console.log(index)
}) 

3、while循环更优

// example1 
for (let i = 0; i < 10;i++) {
  console.log(i)
}
// example2- fastest
let i = 0
while(i < 10) {
  console.log(i)
  i++
}

直接量替换new Object

  • 使用字面量的方式代替构造式
// example1
const a = new Array(3) // 涉及函数调用,消耗更多一点
a[0] = 1
a[1] = 2
a[2] = 3 
// example2- fastest
const a = [1, 2, 3] 

文档碎片优化节点添加

  • 减少回流重绘
// example1
for (var i = 0; i< 10; i++) {
  var op = document.createElement('p')
  op.innerHTML = i
  document.body.appendChild(op)
}
// example2- fastest
const frgEle = document.createDocumentFragment()
for (var i = 0; i< 10; i++) {
  var op = document.createElement('p')
  op.innerHTML = i
  frgEle.appendChild(op)
}
document.body.appendChild(frgEle)

克隆优化节点操作

  • 克隆一个节点比创建一个节点速度更快
// example1
for (var i = 0; i< 3; i++) {
    var op = document.createElement('p')
    op.innerHTML = i
    document.body.appendChild(op)
  }
// example2- fastest
const oldEle = document.getElementById('box1')
for (var i = 0; i< 10; i++) {
  var op = oldEle.cloneNode(false)
  op.innerHTML = i
  document.body.appendChild(op)
}