由于上一篇文字数量超出限制所以js代码优化部分写在这里
上一篇地址:juejin.cn/post/688341…
第三部分:JS性能优化
十九:代码优化介绍
- 如何精准测试JavaScript性能--本质上就是采用执行样本进行数学统计和分析
- 可以使用jsbench.me/完成
二十:慎用全局变量
-
为什么要慎用
-
全局变量定义存在全局执行上下文,是所有作用域链的顶端
-
全局执行上下文一直存在于上下文执行栈,直到程序退出
-
如果某个局部作用域出现了同名变量则会遮蔽或者污染
//全局 var i,str = ""; for (i = 0; i < 1000; i++) { str += i; } //局部 for (let i = 0; i < 1000; i++) { let str = ""; str += i; }
二十一:缓存全局变量
- 将使用中无法避免的全局变量缓存到局部(比如查找Dom元素,必须使用到document)
//没有使用缓存
function getBtn1() {
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");
}
//使用了缓存
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");
}
二十二:通过原型对象添加附加方法
-
通过原型新增方法
-
在原型对象上新增实例对象需要的方法
// 没有使用原型对象;
var fn1 = function () {
this.foo = function () {
console.log(11111);
};
};
let f1 = new fn1();//使用原型对象
var fn2 = function () {};
fn2.prototype.foo = function () {
console.log(11111);
};
let f2 = new fn2();
二十三:避开闭包的陷阱
//闭包特点
function foo1() {
var name = "xjq";
return function fn() {
console.log(name);
};
}
foo1()();
//闭包陷阱(产生内存泄漏)
function foo2() {
var el = document.getElementById("btn");
el.onclick = function () {
console.log(el.id);
};
//演示
//优化--解决内存泄漏--释放内存空间
el = null;
}
foo2();
二十四:避开属性访问方法使用
-
JavaScript中的面向对象
-
JS属性不需要属性的访问方法,所有属性都是外部可见的
-
使用属性访问方法只会加一层重定义,没有访问的控制力
//使用属性访问
function Person1() {
this.name = "icoder";
this.age = 18;
this.getAge = function () {
return this.age;
};
}
const p1 = new Person1();
const a = p1.getAge();//不使用属性访问
function Person2() {
this.name = "icoder";
this.age = 18;
}
const p2 = new Person2();
const b = p2.age;
二十五:循环优化
var aBtns = document.getElementsByClassName("btn");
for (let i = 0; i < aBtns.length; i++) {
console.log(i);
}
//缓存aBtns长度,就不需要向上面的for一样,每次的获取length
for (let i = 0, len = aBtns.length; i < len; i++) {
console.log(i);
}
二十六:选择最优的循环方案
-
foreach
-
for
-
for..in
//三中不同的循环-foreach优于for优于for-in
var arrlist = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9);
arrlist.forEach(function (item) {
console.log(item);
});for (let i = 0, len = arrlist.length; i < len; i++) {
console.log(arrlist[i]);
}
for (let i in arrlist) {
console.log(arrlist[i]);
}
二十七:文档碎片化优化节点
-
节点添加优化
-
节点的添加必然会有回流和重绘
for (var i = 0; i < 10; i++) {
var oP = document.createElement("p");
oP.innerHTML = i;
document.body.appendChild(oP);
}//优化
//创建一个容器
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);
二十八:克隆优化节点操作
//克隆节点优于普通的
for (var i = 0; i < 10; i++) {
var oP = document.createElement("p");
oP.innerHTML = i;
document.body.appendChild(oP);
}
//优化--节点克隆
var oldP = document.getElementById("box1");
for (var i = 0; i < 10; i++) {
var newP = oldP.cloneNode(false);
newP.innerHTML = i;
document.body.appendChild(newP);
}
二十九:直接量替换new Object
//直接字面量
var a = [1, 2, 3];
//new Object
var b = new Array(3);
b[0] = 1;
b[1] = 2;
b[2] = 3;
三十:减少层级判断
//减少层级判断的代码快于没减少的
function doSomething(part, chapter) {
const parts = ["ES2016", "工程化", "Vue", "React", "Node"];
if (part) {
if (parts.includes(part)) {
console.log("没有该课程");
if (chapter > 5) {
console.log("你不是vip");
}
}
} else {
console.log("没有输出课程");
}
}
doSomething("ES2016", 6);
//减少判断层级
function doSomething1(part, chapter) {
const parts = ["ES2016", "工程化", "Vue", "React", "Node"];
if (!parts) {
console.log("没有输出课程"); return;
}
if (!parts.includes(part)) return;
console.log("没有该课程");
if (chapter > 5) {
console.log("你不是vip");
}
}
doSomething1("ES2016", 6);
三十一:减少作用域链查找层级
-
下面案例优化了但是是有空间换了时间
var name = "xjq";
function foo() {
name = "xjq666"; //此处的name是属于全局的
function bar() {
var age = 38;
console.log(age);
console.log(name); //这里沿着bar向上查找,在沿着foo查找到全局作用域才找到name
}
bar();
}
foo();//优化
var name = "xjq";
function foo() {
var name = "xjq666"; //此处的name是属于foo的
function bar() {
var age = 38;
console.log(age);
console.log(name); //这里沿着bar向上查找,在着foo查找到name
}
bar();
}
foo();
三十二:减少数据读取次数
-
栈区的数据访问较快
-
堆区的数据访问较慢,因为需要按照引用的关系找到对应的位置
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 test = () => {
let obj = new Object();
obj.name = "xjq";
obj.age = 22;
obj.slogan = "123456";
return obj;
};
let test = () => {
let obj = {
name: "xjq",
age: 22,
slogan: "123456",
};
return obj;
};
// test();
console.log(test());
//基本数据类型--使用字面量的优于使用构造式的,而且差异较大
var str1 = "xjq";
var str2 = new String("xjq");
三十四:减少循环体中活动
-
可以提取不必要的代码到循环体外执行(经常使用且不变的值)
var test = () => {
var i;
var arr = ["xjq", 22, "男"];
for (i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
};//优化
var test = () => {
var i;
var arr = ["xjq", 22, "男"];
var len = arr.length;
for (i = 0; i < len; i++) {
console.log(arr[i]);
}
};//while循环----while优于for--因为while是从后往前
var test = () => {
var arr = ["xjq", 22, "男"];
var len = arr.length;
while (len--) {
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;
};
test(oBox);
var test = () => {
var name = "xjq";
var age = 22;
var slogan = "123456";
return name + age + slogan;
};
//优化
var test = () => {
var name = "xjq",
age = 22,
slogan = "123456";
return name + age + slogan;
};
test();
三十六:采用事件绑定
<ul id="ul">
<li>x</li>
<li>j</li>
<li>q</li>
</ul>
var list = document.querySelectorAll("li");
function showTxt(ev) {
console.log(ev.target.innerHTML);
}
for (let item of list) {
item.onclick = showTxt;
}
var oUI = document.getElementById("ul");
oUI.addEventListener("click", showTxt, true);