1. 避免阻塞渲染:
页面渲染会因JavaScript执行而暂停,尤其是内联脚本和document.write()的使用。
<script>document.write("Today is " + new Date().toDateString());</script>
2. 慎用with语句:它增加作用域链搜索,影响性能。
和函数类似 ,with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度,由于额外的作用域链的查找,在with语句中执行的代码肯定会比外面执行的代码要慢,在能不使用with语句的时候尽量不要使用with语句。
// 使用with语句前
with(someObject) {
console.log(property);
}
// 使用with语句后
console.log(someObject.property);
3. 优化数据访问:局部变量访问速度优于对象属性和数组元素,多次访问应使用局部变量缓存。
const array = someObject.array;
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
4. 减少全局变量访问:局部变量访问速度比全局变量快。
function search() {
const location = window.location;
alert(location.href);
}
5. 合理放置脚本标签:置于HTML底部以减少对页面渲染的阻塞。
优化 JavaScript 的首要规则:将脚本放在底部。
<body>
<!-- 页面内容 -->
<script src="script.js"></script>
</body>
6. 慎用闭包:它们可能导致作用域链中的性能问题,特别是在循环中。
闭包基本上被认为是JavaScript中的new,当我们定义一个即时函数的时候,我们就使用了闭包,比如:
document.getElementById('foo').onclick = function(ev) { };
7. 优化循环:避免在循环中重复声明和检查变量。
for (let i = 0; i < 10; i++) {
// 循环体
}
8. 使用XHR加载脚本:可异步下载并执行脚本,避免阻塞。
var xhr = new XMLHttpRequest();
xhr.open("GET", "script.js", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
eval(xhr.responseText);
}
};
xhr.send(null);
9. 减少NodeList访问:缓存NodeList结果并减少访问次数。
最小化访问NodeList的次数可以极大的改进脚本的性能
var images = document.getElementsByTagName('img');
for (var i = 0, len = images.length; i < len; i++) {}
编写JavaScript的时候一定要知道何时返回NodeList对象,这样可以最小化对它们的访问:
1、进行了对getElementsByTagName()的调用
2、获取了元素的childNodes属性
3、获取了元素的attributes属性
4、访问了特殊的集合,如document.forms、document.images等等
要了解了当使用NodeList对象时,合理使用会极大的提升代码执行速度
10. 避免与null比较:使用typeof或instanceof进行类型检查。
由于JavaScript是弱类型的,所以它不会做任何的自动类型检查,
所以如果看到与null进行比较的代码,尝试使用以下技术替换:
1、如果值应为一个引用类型,使用instanceof操作符检查其构造函数
2、如果值应为一个基本类型,作用typeof检查其类型
3、如果是希望对象包含某个特定的方法名,
则使用typeof操作符确保指定名字的方法存在于对象上
11. 尊重对象所有权:不要修改不属于你的对象。
因为JavaScript可以在任何时候修改任意对象,这样就可以以不可预计的方式覆写默认的行为,
所以如果你不负责维护某个对象,它的对象或者它的方法,那么你就不要对它进行修改,具体一点就是说:
1、不要为实例或原型添加属性
2、不要为实例或者原型添加方法
3、不要重定义已经存在的方法
4、不要重复定义其它团队成员已经实现的方法,永远不要修改不是由你所有的对象,
你可以通过以下方式为对象创建新的功能:
1、创建包含所需功能的新对象,并用它与相关对象进行交互
2、创建自定义类型,继承需要进行修改的类型,然后可以为自定义类型添加额外功能
12. 避免循环引用:可能导致内存泄漏。
下面2种方法可以解决循环引用:
1、置空dom对象
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {
//……
}
}
init();
//可以替换为:
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {
//……
}
el = null;
}
init();
2、构造新的context
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {
//……
}
}
init();
//可以替换为:
function elClickHandler() {
//……
}
function init() {
var el = document.getElementById('MyElement');
el.onclick = elClickHandler;
}
init();
13. 字符串连接优化:使用模板字符串或数组join方法。
如果要连接多个字符串,应该少使用+=,如
s+=a;
s+=b;
s+=c;
应该写成s+=a + b + c;
而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,
最好使用一个缓存,使用JavaScript数组来收集,最后使用join方法连接起来。
14. 类型转换:直接使用适当的类型,避免不必要的转换。
var myVar = "3.14159",
str = "" + myVar, //转成string类型
i_int = ~ ~myVar, //转成int类型
f_float = 1 * myVar, //转成浮点型
b_bool = !!myVar, /* 转成布尔类型,任何长度不为0的字符串和除0以外的任何数字都为真*/
array = [myVar]; // 转成数组
如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高。
15. 使用字面量创建对象和数组。
var aTest = new Array(); //替换为
var aTest = [];
var aTest = new Object; //替换为
var aTest = {};
var reg = new RegExp(); //替换为
var reg = /../;
//如果要创建具有一些特性的一般对象,也可以使用字面量,如下:
var oFruit = new Object;
oFruit.color = "red";
oFruit.name = "apple";
//前面的代码可用对象字面量来改写成这样:
var oFruit = { color: "red", name: "apple" };
16. 避免双重解释:如使用eval或Function构造器。
如果要提高代码性能,尽可能避免出现需要按照JavaScript解释的字符串,也就是
1、尽量少使用eval函数
使用eval相当于在运行时再次调用解释引擎对内容进行运行,需要消耗大量时间,而且使用Eval带来的安全性问题也是不容忽视的。
2、不要使用Function构造器
不要给setTimeout或者setInterval传递字符串参数。
var num = 0;
setTimeout('num++', 10);
//可以替换为:
var num = 0;
function addNum() {
num++;
}
setTimeout(addNum, 10);
17. 简化否定检测:使用逻辑非操作符。
if(oTest != '#ff0000'){
//do something
}
if(oTest != null){
//do something
}
if(oTest != false){
//do something
}
//虽然这些都正确,但用逻辑非操作符来操作也有同样的效果:
if(!oTest){
//do something
}
18. 释放对象引用:帮助垃圾回收。
在rich应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让GC能够回收这些内存控件。
对象:obj = null
对象属性:delete obj.myproperty
数组item:使用数组的splice方法释放数组中不用的item
19. 性能注意事项:使用原生方法,优化switch语句,利用位运算符,巧用布尔运算符。
1、尽量使用原生方法
2、switch语句相对if较快
通过将case语句按照最可能到最不可能的顺序进行组织
3、位运算较快
当进行数字运算时,位运算操作要比任何布尔运算或者算数运算快
4、巧用||和&&布尔运算符
function eventHandler(e) {
if (!e) e = window.event;
}
//可以替换为:
function eventHandler(e) {
e = e || window.event;
}
-------------------------------------------------------------
if(myobj){
doSomething(myobj);
}
//可以替换为:
myobj && doSomething(myobj);
20. 代码风格:使用清晰的代码风格,避免不必要的类型声明和赋值。
1、每条语句末尾须加分号
在if语句中,即使条件表达式只有一条语句也要用{}把它括起来,以免后续如果添加了语句之后造成逻辑错误
2、使用+号时需谨慎
JavaScript 和其他编程语言不同的是,在 JavaScript 中,’+'除了表示数字值相加,字符串相连接以外,还可以作一元运算符用,把字符串转换为数字。因而如果使用不当,则可能与自增符’++’混淆而引起计算错误
var valueA = 20;
var valueB = "10";
alert(valueA + valueB); //ouput: 2010
alert(valueA + (+valueB)); //output: 30
alert(valueA + +valueB); //output:30
alert(valueA ++ valueB); //Compile error
3、使用return语句需要注意
一条有返回值的return语句不要用()括号来括住返回值,如果返回表达式,则表达式应与return关键字在同一行,以避免压缩时,压缩工具自动加分号而造成返回与开发人员不一致的结果
function F1(){
var valueA = 1;
var valueB = 2;
return valueA + valueB;
}
function F2() {
var valueA = 1;
var valueB = 2;
return
valueA + valueB;
}
alert(F1()); //输出: 3
alert(F2()); //输出: undefined
==和===的区别
避免在if和while语句的条件部分进行赋值,如if (a = b),应该写成if (a == b),但是在比较是否相等的情况下,最好使用全等运行符,也就是使用===和!==操作符会相对于==和!=会好点。==和!=操作符会进行类型强制转换。
ar valueA = "1";
var valueB = 1;
if(valueA == valueB) {
alert("Equal");
}
else{
alert("Not equal");
}
//输出: "Equal"
if(valueA === valueB){
alert("Equal");
}
else{
alert("Not equal");
}
//输出: "Not equal"
不要使用生偏语法
函数返回统一类型
总是检查数据类型
何时用单引号,何时用双引号
建议在HTML中使用双引号,在JavaScript中使用单引号,但为了兼容各个浏览器,也为了解析时不会出错,定义JSON对象时,最好使用双引号。
21. 部署:使用JSLint验证,压缩JS文件,统一UTF-8编码,将JavaScript代码放在外部文件中,并在HTML底部引用。
1、用JSLint运行JavaScript验证器来确保没有语法错误或者是代码没有潜在的问题。
2、部署之前推荐使用压缩工具将JS文件压缩。
3、文件编码统一用UTF-8。
4、JavaScript 程序应该尽量放在 .js 的文件中,需要调用的时候在 HTML 中以 <script src=”filename.js”> 的形式包含进来。JavaScript 代码若不是该 HTML 文件所专用的,则应尽量避免在 HTML 文件中直接编写 JavaScript 代码。因为这样会大大增加 HTML 文件的大小,无益于代码的压缩和缓存的使用。另外,<script src=”filename.js”> 标签应尽量放在文件的后面,最好是放在标签前。这样会降低因加载 JavaScript 代码而影响页面中其它组件的加载时间。