1.全局变量Vs局部变量
case:
// bad
var i
var s = ''
for (i = 0; i < 1000; i++) {
s += i
}
// good
for (let i = 0; i < 1000; i++) {
let s = ''
s += i
}
测试结果:
image.png
结论:尽量使用let代替var关键字缩小作用域。
2.全局变量的缓存Vs不缓存
case:
// bad
function getBtn() {
let oBtn1 = document.getElementById('btn1')
let oBtn3 = document.getElementById('btn3')
let oBtn5 = document.getElementById('btn5')
let oBtn7 = document.getElementById('btn7')
let oBtn9 = document.getElementById('btn9')
}
// good
function getBtn2() {
let obj = document
let oBtn1 = obj.getElementById('btn1')
let oBtn3 = obj.getElementById('btn3')
let oBtn5 = obj.getElementById('btn5')
let oBtn7 = obj.getElementById('btn7')
let oBtn9 = obj.getElementById('btn9')
}
测试结果:
image.png
结论:局部缓存全局变量比不缓存的优势不是那么明显
3.方法添加到构造方法里Vs添加到原型链上
case:
// bad
let fn1 = function () {
this.hello = function() {
console.log('hello')
}
}
let f1 = new fn1()
// good
let fn2 = function() {}
fn2.prototype.hello = function() {
console.log('hello')
}
let f2 = new fn2()
测试结果:
image.png
结论:方法添加到原型链上比放到构造方法里,构造对象的速度更快
问题:如果f1,f2分别调用hello(),测试的结果却是相反的,为何?
image.png
4.直接获取属性值Vs调用属性getter方法
case:
// setup
class Person {
name = undefined
age = undefined
getAge() {
return this.age
}
}
let p = new Person()
p.name = 'james'
p.age = 18
// bad
let n2 = p.getAge()
// good
let n1 = p.name
测试结果:
image.png
结论:直接获取属性值比调用getter方法性能上稍微好一些
5. 添加大量标签:直接添加Vs使用文档碎片分步添加
case:
// bad
for (var i = 0; i < 10; i++) {
var oP = document.createElement('p')
oP.innerHTML = i
document.body.appendChild(oP)
}
// good
const fragEle = document.createDocumentFragment()
for (var i = 0; i < 10; i++) {
var oP = document.createElement('p')
oP.innerHTML = i
fragEle.appendChild(oP)
}
document.body.appendChild(fragEle)
测试结果:
image.png
结论:添加大量标签时,先添加到createDocumentFragment,然后再添加到body上比直接添加到body上性能高。
6.添加已经页面上已经存在的相同属性的标签:重新生成Vs克隆
case:
<body>
<p id="box1">old</p>
<script>
// bad
for (var i = 0; i < 3; i++) {
var oP = document.createElement('p')
oP.innerHTML = i
document.body.appendChild(oP)
}
// good
var oldP = document.getElementById('box1')
for (var i = 0; i < 3; i++) {
var newP = oldP.cloneNode(false)
newP.innerHTML = i
document.body.appendChild(newP)
}
</script>
</body>
测试结果:
image.png
结论:添加页面上已经存在并且相同属性的标签,应该使用克隆方式添加。
7.字面量创建Vs构造方法创建
字符串
case:
// bad
let s1 = new String('hello')
// good
let s2 = 'hello'
测试结果:
image.png
数字
case:
// bad
let n1 = new Number(10)
// good
let n2 = 10
测试结果:
image.png
布尔
case:
// bad
let b1 = new Boolean(true)
// good
let b2 = true
测试结果:
image.png
数组
case:
// bad
let a1 = new Array()
a1[0] = 1
a1[1] = 2
a1[2] = 3
// good
let a2 = [1, 2, 3]
测试结果:
image.png
Map
case:
// bad
let m1 = new Map()
m1['k1'] = 'v1'
m1['k2'] = 'v2'
// good
let m2 = {'k1': 'v1', 'k2': 'v2'}
测试结果:
image.png
对象
case:
// bad
let o1 = new Object()
o1.name = 'james'
o1.age = 18
// good
let o2 = {name: 'james', age: 18}
测试结果:
image.png
结论:
- 基本类型:使用字面量创建比使用构造方法创建性能上要快95%以上,因为构造方法创建出来的是对象,是引用类型,而基本类型是值类型,他们在底层的实现和存储上的差别是很大的,所以表现出的效率差距也很大。
- 引用类型:使用字面量创建比使用构造方法创建依然有小幅优势。
8.循环方式的比较
由于使用JSBench测试的时候情况很不稳定,所以此处用代码测试时间。
因为for in 在数据量很大的情况下非常慢,case中已忽略for in的比较,因为它的效率是最低的。
case:
var a1 = new Array(1000000).fill(1)
var iteranum = 1000
// 遍历
// 1.常规for循环
console.time('for')
for(let k = 0; k < iteranum; k++) {
for (let i = 0; i < a1.length; i++) {
//console.log(a1[i])
let j = a1[i] + 1
}
}
console.timeEnd('for')
// 2.常规for循环(优化)
console.time('for2')
for(let k = 0; k < iteranum; k++) {
for (let i = 0, l = a1.length; i < l; i++) {
//console.log(a1[i])
let j = a1[i] + 1
}
}
console.timeEnd('for2')
// 3.for of
console.time('for of')
for(let k = 0; k < iteranum; k++) {
for (let v of a1) {
//console.log(v)
let j = v + 1
}
}
console.timeEnd('for of')
// // 4.for in
// console.time('for in')
// for(let k = 0; k < iteranum; k++) {
// for (let v in a1) {
// //console.log(a1[v])
// let j = a1[v] + 1
// }
// }
// console.timeEnd('for in')
// 5.forEach
console.time('forEach')
for(let k = 0;k < iteranum; k++) {
a1.forEach(function(e) {
//console.log(e)
let j = e + 1
})
}
console.timeEnd('forEach')
测试机器:
CPU: 3.1 GHz 双核Intel Core i5
内存:8 GB 2133 MHz LPDDR3
测试结果(多次运行,各数据浮动不大):
for: 792.904ms
for2: 693.385ms
for of: 1831.124ms
forEach: 13303.218ms
结论:
在循环次数很大的情况下,遍历效率
for(缓存长度) > for > for of > forEach > for in