Javascript 优化项目代码技巧之语言基础(二)
博客逐步迁移至 极客兔兔的小站
上一篇随笔介绍了如何正确判断对象类型、避免变量污染,特殊值(null、undefined、NaN)的使用,以及其他Javascript中常用关键字与方法的优化,这篇随笔将着重介绍Javascript语言中的条件与循环优化。
如有问题,请不吝指出,非常感谢;如果喜欢,右下角点个推荐吧~
1.if、switch、查表
1.1 if-else分治策略
// 方法一,假设value的值平均分布
// 方法一的平均查询次数是 (n+1)/2,即复杂度是O(N)
// 方法二采用了二分查找,平均查找次数为lg(n),复杂度是对数级别的
if(value === 0){
func0();
} else if (value === 1){
func1();
} else if (value === 2){
func2();
} else if (value === 3){
func3();
} else if (value === 4){
func4();
} else if (value === 5){
func5();
} else if (value === 6){
func6();
} else if (value === 7){
func7();
}
// 方法二(分治策略),为方便排版,压缩、省略部分代码块
if (value < 4) {
if(value < 2){
if(value === 0){ func0(); }
else { func1(); }
}else {
if(value === 2){ func2(); }
else { func3(); }
}
} else {
// 省略同上的结构...
}
- 优化技巧一:二分查找能够显著降低复杂度,提高性能,上述例子只是其中一个,在项目中涉及到判断,查找而数据量较大时可以考虑二分提高性能。
- 优化技巧二:对于if-else语句,判断情况较少,或者考虑代码可读性(比如判断周一到周五),方法一会更直观,不能一味追求效率。
- 优化技巧三:如果判断值不是平均分布的,那么考虑将出现频率高的判断放在前面(上例中如果90%情况下value等于7,几乎每次都要判断8次,如果将这个判断放在最前面,就降到了1次)。
1.2 什么情况下用switch
- switch-case语句利用转发表,快速定位入口,在数据量较大时,switch-case执行效率会比if-else好很多。
- 数据量较多时,switch-case的可读性也会好很多。
- 以下情况适合用switch
(1) 判断值超过2个,而且值是离散的。 例如 case '男'
(2) 表达式的值是固定的,不是动态变化的
(3) 表达式的值值一般为整数、字符串等类型的数据
1.3 使用查表提高性能
- 当有大量离散值需要测试时,如果有一张转发表可以直接查询,那么无疑可以极大地提高性能,如果将这个表以字典(dict)的形式呈现,可读性也得到了提高。Javascript中字典往往等价于对象,举两个例子:
/* 适用情况一:条件执行代码很少,如使用if或switch显得笨重 */
function func1(key){
if(key === 0){ return ans0; }
if(key === 1){ return ans1; }
// 省略 2,3,4,5...
}
// 替换为
function func1(key){
var ans = [ans0,ans1,ans2,ans3 ... ];
return ans[key];
}
/* 适用情况二:条件执行代码很多,如用if或switch可读性很差
* 同时,执行代码可能多次复用,而且整体性较强
* 这种写法常用在javasript框架中,书写钩子函数(Hook)
* 可读性很高,而且容易扩展,代码本身即文档
*/
function func1(key){
if(key === "created"){ /* ... 省略10行代码 */ }
else if(key === "init"){ /* ... 省略10行代码 */ }
// 省略 "resume","start","pause","destroy",...
}
// 替换为
var hooks = {
"created": function(){ /* ... 省略10行代码 */ };
"init": function(){ /* ... 省略10行代码 */ };
// ... 省略更多属性
}
function func1(key){
hooks[key]();
}
2.短路表达式(&&和||)
2.1 改善 && 与 || 性能
- 使用&&运算时,从左到右计算表达式,一旦为false就返回,例如:
A && B,如果A为false,表达式返回false,不再计算B。
A为true,会继续计算B,再决定返回值,这称为短路表达式
因此,如果B为false的概率大于A,写为B && A可以减少计算次数
- 使用||运算时,同样先计算||左侧的表达式,例如:
A || B,如果A为true,表达式返回true,不再计算B。
因此,如果B为true的概率大于A,写为B || A可以减少计算次数
2.2 巧用短路表达式赋值
- && 与 || 不仅用在判断语句中,常用在赋值语句中
a = {} || [] // => a = {},a并没有被赋值为true,而是 {}
- 利用javascript的弱类型,我们可以构造很精巧的赋值表达式,0、""、null、false、undefined、NaN 判断为false,其他为true
/* || */
var value = a || [];
// 等价于
value = a ? a : [];
// 等价于
if(a){ value = a; }
else { value = []; }
/* && */
var value = a && b;
// 等价于
value = a ? b : a;
- 当表达式较简单时,使用三目运算符也能让我们的代码很优雅,但是当表达式数量很多时,&&和||能更优雅。
/* 当a和b均返回false时,返回一个新建对象 */
return a || b || {};
/* jQuery中大量使用短路表达式赋值
* 代码过于简洁,代码可读性会降低,适当使用
*/
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
(~b.sourceIndex || MAX_NEGATIVE) -
(~a.sourceIndex || MAX_NEGATIVE);
- Javascript的弱类型使得短路表达式赋值很容易,但是有时我们需要明确返回一个布尔值,这个时候可以强制类型转换。
var value = !!( a || b) // => value = true/false
if(!!(a && b)) // => 显式转换,与if(a && b)结果一致
3.循环优化
3.1 少用 forEach
- Javascript的数组有一个原型方法:forEach,可以在每一个成员上执行一个函数,forEach接收3个参数,数组项的值(value),数组项的索引(index),以及数组自身(array)
- forEach 相比一般的循环,将关联额外的函数调用,如果将forEach改为普通的循环结构,效率将大大提高。
items = [1,2,3];
items.forEach(function(value,index,array) {
// ... func(value);
})
// 等价于
var len = items.length;
for(var i = 0; i < len; ++i ){
// ... func(items[i]);
}
3.2 重复变量暂存
- 在循环中,重复使用一个变量的情况是十分常见的,例如上个例子的中
len
,如果不使用变量len暂存,那么每次循环都需要访问数组的length
属性,比起直接访问一个数字,访问一个对象属性的花销会更大。 - 变量暂存在这个例子中优势并没有那么明显,但是如果循环中进行了DOM操作,我们知道DOM操作是相当费时的,如果将DOM对象缓存,性能提高就很可观了。
// 暂存变量前,获取 p#item,需要3次DOM操作,
$('p#item').func1();
$('p#item').func2();
$('p#item').func3();
// 等价于(这里不考虑jQuery的链式操作)
// 只需要一次DOM操作(DOM操作非常耗时)
var p_item = $('p#item');
p_item.fun1();
// ...
- 重复使用的需要计算的变量赋值给另一个变量,还有一个好处是易于压缩,考虑下面的例子
/* 不暂存变量 */
var obj = { nickname:{} };
obj['nickname'].firstname = 'Tom';
obj['nickname'].lastname = 'Smith';
obj['nickname'].fullname = 'Tom Smith';
// 压缩结果
var a = { nickname:{} };
a['nickname'].firstname = 'Tom';
a['nickname'].lastname = 'Smith';
a['nickname'].fullname = 'Tom Smith';
/* 暂存变量 */
var obj = { nickname:{} };
var nickname = obj['nickname'];
nickname.firstname = 'Tom';
nickname.lastname = 'Smith';
nickname.fullname = 'Tom Smith';
// 压缩结果如下
var a = { nickname:{} };
var b = a['nickname'];
b.firstname = 'Tom';
b.lastname = 'Smith';
b.fullname = 'Tom Smith';
- 实际项目中,Javasript文件的代码动辄上万行,变量暂存之后,对性能影响以及压缩后节省的空间不可小视,定义变量时,不妨慷慨一点。
分享创造价值,喜欢这个系列文章,不妨关注一下~
Javascript 优化项目代码技巧之语言基础(二)的更多相关文章
- Javascript 优化项目代码技巧之语言基础(一)
Javascript的弱类型以及函数作用域等规则使用编写Javascript代码极为容易,但是编写可维护.高质量的代码却变得十分困难,这个系列的文章将总结在项目开发过程中,能够改善代码可读性. ...
- 优化 PHP 代码技巧
优化 PHP 代码技巧1. 如果一个方法能被静态,那就声明他为静态的,速度可提高 1/4;2. echo 的效率高于 print,因为 echo 没有返回值,print 返回一个整型;3. 在循环之前 ...
- 手把手写代码学习C语言基础
- Java语言基础二
1.常量的概述和使用 A:什么是常量 B:Java中常量的分类 常量分类为六种:a.”字符串” b.’字符’ c.整数 d.小数 e.boolern(布尔类型) 返回值为 FALSE和TRUE ...
- 01C语言基础(二)
Day07 笔记 指针和函数: 栈 帧: 当函数调用时,系统会在 stack 空间上申请一块内存区域,用来供函数调用,主要存放 形参 和 局部变量(定义在函数内部). 当函数调用结束,这块内存区域自动 ...
- C语言基础二(敲打键盘、寻找资料)
看过很多资料的人,估计发觉了什么,我上篇的基础一其中一个最致命的错误,没有加return 0; 为什么不加,说真的,我留个坑,所以跳跃性的直接说到函数是如何运用的. 上章说到main就是主入口,根据m ...
- Go语言基础二:常用的Go工具命令
常用的Go工具命令 Go附带了一下有用的命令,这些命令可以简化开发的过程.命令通常包含的IDE中,从而使工具在整个开发环境中保持一致. go run 命令 go run命令实在开发过程中执行的最常见的 ...
- C语言基础--二维数组
二维数组概念: 数组中的每一个元素又是一个数组, 那么这个数组就称之为二维数组,二维数组是特殊的一维数组. 二维数组格式: 元素类型 数组名称[一维数组的个数][每个一维数组的元素个数]; 元素类型 ...
- R语言基础(二) 可视化基础
> which.max(apply(x[c("x1","x2","x3")], 1, sum))49 > x$num[which ...
随机推荐
- javascript学习笔记2-typeof、Number类型、Boolean()
1.typeof操作符 对一个值使用typeof操作符可能返回下列某个字符串 "undefined"——这个值未定义 "boolean"——这个值是布尔值 &q ...
- 清除Windows的DNS缓存
最近ESET杀毒软件老是提示受到DNS缓存攻击,然后就不能打开网页,或者打开得很慢.这是由于缓存的DNS被更改,访问的是错误的IP地址造成的. 解决的办法就是清除DNS缓存,打开DOS命令窗口,先后输 ...
- MySQL带参数的存储过程小例子
http://wwty.iteye.com/blog/698239 mysql存储过程也提供了对异常处理的功能:通过定义HANDLER来完成异常声明的实现 语法如下: DECLARE handler_ ...
- Hack语言类型化简介
在typechecker的配合下,Hack语言的类型化能力是Hack其他功能特性的基石.开发Hack语言的主要动机也正是为代码提供显式类型标注以便对代码进行类型一致性和潜在错误分析. 这是用于对比Ha ...
- c语言是如何实现泛型链表
最近有看一点Linux内核源码,发现内核里大量使用了list_head结构体.百度查了一下,原来内核利用这个结构体实现了泛型. 自认为对链表已经很熟悉的我,决定自己实现一下. 下面以Node和list ...
- GJM : Unity3D结合ZXING制作二维码识别
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- 学习angular.js的一些笔记想法(上)
1.data-ng-app与ng-app的区别 data-ng-app是为了h5不报错 2.ng-class 不多说就来拿例子说吧 html代码 <div class='color-change ...
- 24个很赞的 Node.js 免费教程和在线指南
JavaScript 最初是用来创建动态网站效果的的前端语言.而如今,这门脚本语言也可以用作后端开发,用于搭建 Web 服务器,开发接口,甚至创建博客.在下面这个列表中包括24个 Node.js 教程 ...
- js编写当天简单日历
之前一直很想用javascript写一个日历,但是因为完全没有好的思路, 所以迟迟没有尝试.最近在网上刚好看到用javascript编写的简单日历的例子,代码量虽然不大, 但是我觉得很好地阐述了js日 ...
- webstorm常用的快捷键总结
1. ctrl + shift + n: 打开工程中的文件,目的是打开当前工程下任意目录的文件. 2. ctrl + j: 输出模板 3. ctrl + b: 跳到变量申明处 4. ctrl + al ...