从本文你将了解到
- JSBench的使用
- 堆栈JS执行过程的介绍
- 减少层级判断
- 减少作用域链查找层级
- 减少数据读取次数(缓存)
- 字面量与构造式
- 减少循环体中活动
- 减少声明及语句数(未频繁使用的可以不声明)
- 采用事件绑定(委托)
JSBench使用
链接地址:https://jsbench.me/,ops越大越好,每秒执行次数。由于浏览器多线程,尽可能一个标签页进行测试,测试过程中不要切换线程,保持数据的准确性
图解堆栈中代码执行流程
let a = 10
function foo(b){
let a = 2
function baz(c){
console.log(a+b+c)
}
return baz
}
let fn = foo(2)
fn(3)
- 执行环境栈用于存放我们的执行上下文(ECStack 执行环境栈)
- 环境栈内的全局执行环境率先被压入栈(EC全局global执行上下文)
代码执行时,EC全局 VO变量对象
- a=10 存在栈内存中
- foo= 函数,由于是函数,会开辟一个指针为AB1的堆内存,并将指针AB1指向foo(即foo=AB1)
- 指针为AB1的堆中含有
function foo(b){...}
name:foo
length:1
- 继续执行,到
fn = foo(2)
时,会开辟一个函数foo的执行上下文 EC(foo) EC(foo) 初始化this = window, 作用域链向外<foo.AO,VO>,AO变量对象
- arguments:{0:2}
- b = 2
- a = 2
- baz = 函数,由于是函数,会开辟一个指针为AB2的堆内存,并将指针AB2指向baz(即baz=AB2)
- 指针为AB2的堆中含有
function baz(c){...}
name:baz
length:1
- 继续执行,到
fn(3)
时,会开辟一个函数baz的执行上下文 EC(baz) EC(baz) 初始化this = window, 作用域链向外<baz.AO,foo.AO,VO>,AO变量对象,AO变量对象
- arguments:{0:3}
- c = 3
- console.log(a+b+c)
- 减少判断层级
尽量减少if..else.. 使用return代替
对于明确的条件分支建议用switch..case代替else if()..
else if只适合区间判断
function doSomething(part,chapter){
const parts = ["ES2016","TOM","jack","React"]
if(part){
console.log("请确认模块信息")
return;
}
if(!parts.includes(part)) return;
console.log("属于当前课程")
if(chapter <= 5) return;
console.log("您需要提供VIP身份")
}
doSomething("ES2016",6)
减少作用域链查找层级
var name = "zca" function foo(){ name = "mcgee" //这里的name在全局声明,这里只是赋值 function baz(){ var age = 38 console.log(age) console.log(name) } baz() } foo()
时间更快的写法,(时间换空间的方式)
里面又var了,新声明会在内存开辟新空间,占内存。如果name数据量特别大,反而上面更好,(空间换时间)
var name = "zca"
function foo(){
var name = "mcgee" //这里的name属于foo内的
function baz(){
var age = 38
console.log(age)
console.log(name)
}
baz()
}
foo()
- 减少数据读取次数
每次都会查找ele对象,将ele对象缓存
..html..
<div id="skip" class="skip"></div>
..js..
var oBox = document.getElementById("skip")
// function hasEle(ele,cls){
// return ele.className == cls
// }
function hasEle(ele,cls){
var clsname = ele.className
return clsname == cls
}
console.log(hasEle(oBox,'skip'))
- 字面量与构造式
对于对象类型字面量形式略优于构造函数形式,对于基本类型字面量远优于构造函数式
通过函数式创建对象
let tests = ()=>{
let objs = new Object()
objs.name="mcgee"
objs.age=18
return objs
}
通过字面量创建对象
let tests = ()=>{
let objs = {
name:"mcgee",
age:18
}
return objs
}
对于基本类型字面量远优于构造函数式
var str1 = "asdaasdsqwe"
var str2 = new String("asdaasdsqwe") //相当于调用函数,多做一些事,扩容更好一些
- 减少循环体活动
循环体内代码越多,执行的越多,效率越慢
将循环体内固定值或者重复的提取出来,
循环方式的选择 for while
var test = ()=>{
var arr = ["mcgee",18,"我为前端而活"]
var i
for(i=0;i<arr.length;i++){
console.log(arr[i])
}
}
var test = ()=>{
var arr = ["mcgee",18,"我为前端而活"]
var i,len=arr.length //固定值缓存
for(i=0;i<len;i++){
console.log(arr[i])
}
}
var test = ()=>{
var arr = ["mcgee",18,"我为前端而活"]
var len=arr.length
while(len--){ //减到0就停掉了 更快
console.log(arr[len])
}
}
减少声明及语句数
这与缓存似乎并不违背,频繁调用的缓存提高运行效率,而非频繁调用或固定值尽量少用声明
<div id="box" style="width:100px;height:100px;"></div>
var oBox = document.getElementById("box")
var test = (ele)=>{
let w = ele.offsetWidth
let h = ele.offsetHeight
return w*h
}
//方式更快,频繁使用的才缓存
var test = (ele)=>{
return ele.offsetWidth*ele.offsetHeight
}
console.log(test(oBox))
又例如
var test = ()=>{
var name="sd"
var age = 18
var str = "55asdada11111"
return name+age+str
}
//方式更快(词法分析,语法分析,语法转换,代码生成)
var test = ()=>{
var name="sd",
age = 18,
str = "55asdada11111"
return name+age+str
}
采用事件委托
利用js元素冒泡的机制,把原本需要去绑定的响应事件的子元素去委托给父元素
<ul id="ul">
<li>mcgee</li>
<li>18</li>
<li>"woaixx"</li>
</ul>
var list = document.querySelectorAll("li")
function showTxt(ev){
var obj = ev.target
if(obj.nodeName.toLowerCase() === 'li')
{
console.log(obj.innerHTML)
}
}
// for(let item of list){
// item.onclick = showTxt
// }
var oUl = document.getElementById("ul")
oUl.addEventListener("click",showTxt,true)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。