Javascript 优化
Javascript 优化
作者:@gzdaijie
本文为作者原创,转载请注明出处:http://www.cnblogs.com/gzdaijie/p/5324489.html
目录
1.全局变量污染与变量提升
2.数据类型
3.特殊值(NaN、undefined、null)
4. === 与 ==
5.没有真正的数组
6.避免使用with与eval
7.消除switch歧义
8.不要省略块标志 { }
Javascript的弱类型以及函数作用域等规则使用编写Javascript代码极为容易,但是编写可维护、高质量的代码却变得十分困难,这个系列的文章将总结在项目开发过程中,能够改善代码可读性、可维护性及优化运行性能的一系列技巧。
如有问题,请不吝指出,非常感谢;如果喜欢,右下角点个推荐吧~
1.全局变量污染与变量提升
- 定义全局变量的3种方式
|
1
2
3
|
var key = 'value'; // 所有函数外执行window.key = 'value'; // window为全局对象key = 'value'; // 省去 var,隐式的全局变量 |
- 全局对象是所有域中都可见的变量,如果程序比较小,那么定义全局变量可以避免函数调用时参数的传递,但是对于一个大的项目,全局变量定义不善,极为容易造成全局变量被某个程序改掉,而没有被发现,这也使调试时难以发现问题所在。
- 在项目较大时,建议尽可能地避免使用全局变量,那么兼顾灵活性与可读性的解决方法就是在程序中只创建一个全局变量。
|
1
2
3
4
5
6
7
8
9
10
|
/** * 只有Person一个全局变量, * 其余变量定义在Person下,尽可能地避免与其他变量名冲突 */var Person = { name:"A", age:20 };Person.parents = { father:"A", mother:"C"}Person.getAge = function() { /* ... */ } |
- 与C、Python等语言拥有块级作用域不同,Javascript作用域是以函数为单位的,定义在函数中的变量函数外部不可见,但是在函数内部(包括其子函数)处处可见。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/** * 考虑下面的函数,先运行f1(),再var b = 4, * 但是事实上,f1()中的b就是之后定义的b * 这是变量提升特性造成的,就是说所有变量定义都将提到函数最前面 * 局部变量的优先级高于外部变量,因此f()外部的b至始至终没有变过 */var b = 15;var f = function() { var a = 100; var f1 = function(){ var c = 3; b = a + c; // => b=103 变量提升,这里的b是函数f()内部的b }; f1(); var b = 4; console.log(a , b , c); // => a=100,b=4,c=undefined}f(); console.log(b); // => b=15,b并没有发生改变 |
2.数据类型
- 浮点数是不精确的,在项目中,特别是在线支付环节,如果希望计算的结果是准确的,一般先乘100转换为整数后,计算完后再除以100,这样能够得到预想中的结果。
|
1
|
0.1 + 0.2 === 0.3 // => false |
- 检测数据类型,我们先看面试中常出现的判断题
|
1
2
3
4
5
6
7
|
typeof null === 'null' // => falsetypeof null === 'object' // => truetypeof NaN === 'NaN' // => falsetypeof NaN === 'number' // => true// javascript6个基本类型如下,typeof总是返回这6个值// number、string、boolean、object、function、undefined// chrome 50中,typeof 3/0 结果为 NaN,有博友知道为什么求告知 |
- typeof null 返回的是'object',项目开发中,我们并不希望null被判断为'object',自定义一个函数,可以满足需求。
|
1
2
3
|
function type(ob){ return (ob === null ) ? "null" : (typeof ob);} |
- 上面的方法不能识别数组、日期等对象,如果需要判断日期、数组、正则、错误等类型,那么可以考虑使用
toString()方法。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 更多内置类型,例如 Math 等可以根据需要添加function type(ob){ var _toString = Object.prototype.toString; var _type = { "undefined" : "undefined", "number" : "number", "boolean" : "boolean", "string" : "string", "[object Function]" : "function", "[object RegExp]" : "regexp", "[object Array]" : "array", "[object Date]" : "date", "[object Error]" : "error" } return _type[typeof ob] || _type[_toString.call(ob)] || (ob ? "object" : "null");} |
- 自定义类型,可结合typeof、constructor属性和instanceof实现
3.特殊值(NaN、undefined、null)
|
1
2
3
4
5
|
typeof NaN === 'number' // => true 类型为number,表示非数字'0.1223' // => 0.1223'1e6' // => 1000000'1a3' // => NaN1.2 + NaN // => NaN |
- Javascript提供了isNaN函数检测NaN值
|
1
2
3
4
5
6
7
8
9
10
11
|
// 不能转换为数字的值,均返回true,// 因此并不能用这个函数检测一个值是否真的为 NaNisNaN(NaN) // => trueisNaN('abc') // => trueisNaN(0) // => falseisNaN('1e6') // => falseisNaN(3/0) // => fasle// NaN是一个唯一自己与自己不相等的值NaN === NaN // false NaN !== NaN // true |
- 如何检查一个值是不是真的NaN
|
1
2
3
4
5
6
7
8
|
// 方法一function _isNaN(value){ return value !== value;}// 方法二function _isNaN(value) { return typeof value === 'number' && isNaN(value);} |
- 使用isFinite检查是否可以是个数或可被转换为一个数
|
1
2
3
4
|
isNaN(3/0) // => fasle,虽然3/0 不能代表一个数,但是isNaN不能识别isFinite(3/0) // => false,isFinite能检测 NaN和正负无穷大isFinite("234") // => true,isFinite 可以将参数转换为数字isFinite(true) // => true,可转化为数字的字符串和布尔值返回true |
- 判断参数是否真的是一个数字,而不是可转换为数字的字符串等
|
1
2
3
4
|
// 加一个基本类型判断就OKfunction isNumber (value) { return typeof value === "number" && isFinite(value);} |
undefined有如下几种情况
(1) 定义了变量但没有赋值 var cc; cc === undefined // => true (2) 获取一个对象不存在的属性 (3) 没有返回值的函数,new + 构造函数除外
(4) 定义函数时声明多个形参,调用时传入参数个数少于声明,多余的参数为undefined
- null 只能显示指定,一般用来清空对象
0、NaN、''(空字符串)、false、null、undefined的布尔值为false(注意,[](空数组),{}(空对象)布尔值为 true )
|
1
2
3
|
var a = 4 ;if({})a++; // => a=5 空对象可通过 Object.keys().length判断if([])a++; // => a=6 空数组通过 length 判断 |
4. === 与 ==
- 使用 == 比较前如果不是相同类型的值,将进行类型转换,转换规则请看下面的例子。
|
1
2
3
4
5
6
7
8
|
'' == 0 // => true,String与Number,将String转为 Number0 == '0' // => true,同上'' == '0'// => false,2个都是字符串,因此直接比较fasle == '0' // => true,Boolean与其他,将Boolean转为Numbertrue == '3' // => false,同上false == undefined // => false,同上,0与undefined不等false == 'false' // => false,同上null == undefined // => true,null与undefined比较返回true |
- === ,如果类型不同,则直接返回false,类型相同再进行比较。
- == 与 != 将进行隐式的类型转换,转换规则复杂,因此在实际的项目开发中,建议避免使用 == 与 !=,尽量使用 === 与 !==。
5.没有真正的数组
- 在Javascript中,数组也是对象,因此typeof的结果是object,如果需要判断一个对象是不是数组,那么可以使用第2部分的toString()方法,当然还可以利用构造函数判断。
|
1
|
typeof value === 'object' && value.constructor === Array |
- 需要注意的是,函数参数arguments并不是数组,只是一个具有length属性,以数字作为键的对象,因此arguments不能使用数组的方法,但是利用上述方法仍将arguments判断为数组。
- 有时我们需要对arguments对象执行数组的某些方法,这个时候可以利用下面的方法将arguments转换为真数组
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/* 将arguments对象转换为数组 */var args = Array.prototype.slice.call(arguments);/* 具有length属性,键为数字且从0开始的对象 */a = {0:"c",1:"d",length:2 }Array.prototype.slice.call(a); // => ["c","d"]/* 没有length属性 */a = {0:"c",1:"d"}Array.prototype.slice.call(a); // => [ ] 空数组/* 猜测slice方法实现方式 */:function slice(ob){ var arr = new Array(); for(var i = 0; i < ob.length; i++ ){ arr[i] == ob[i]; } return arr;} |
6.避免使用with与eval
|
1
2
3
4
5
6
7
|
var ob = { a: 1, b: 2};var d = 0;with(ob){ a = 3; // ob.a = 3 c = 4; // ob.c = undefined,window.c = 4,无心声明了全局变量 d = 5; // ob.d = undefined, d为with外申明的变量} |
不推荐使用with的3个理由
(1) 使用with时,先检查对象是否有该属性,存在则使用,不存在则继续查找作用域,会降低执行性能
(2) with语句中的变量语意不明确,可读性差(3) 例如上例中的c不小心隐式声明为全局变量,本意是给ob.c赋值,易出现问题且难以调试
对于eval(),可以直接执行一段js代码,不推荐理由如下
(1) eval需要将字符串解释为代码后执行,降低执行性能
(2) eval降低程序的可读性,例如 eval("var a = ob." + key)等价于var a=ob[key],后者明显更优(3) eval存在安全问题,任意传入字符串都可能被解析执行,恶意代码也不例外
7.消除switch歧义
- switch中的case语句,定义了函数的起点,却没有定义函数的终点,不要忘记case语句后使用break
- 有时候,我们确实需要贯穿case语句,比如多种case情况,执行同一个方法,这时候,建议显式声明,消除歧义
|
1
2
3
4
5
6
7
8
9
10
11
12
|
// 在需要贯穿的case语句后添加 /* empty */// 避免检查代码时被认为忘记写了执行语句// 显示申明,语意也更明确,提高可读性switch(a){ case 1: /* empty */ case 2: func1(); break; case 3: func2(); break;} |
8.不要省略块标志 { }
- if、while、do、for等语句接受{ ... } 代码块,但是有时我们在代码块中只有一行代码,为了使代码看起来简洁,很可能省略 { },但是这可能产生问题。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
if(a) if(b) func1();else func2();// => 等价于if(a) if(b) func1(); else func2();// 这并不是想要的结果,js不是python,还是加上大括号比较好 |
- 加上括号,也增强了代码的可读性,下面这种写法是不是一目了然了呢
|
1
2
3
4
5
6
7
8
9
|
// 很清晰地看出 if(a) 和 else 并列// if(b) 是 if(a) 的子语句if(a){ if(b){ func1(); }}else{ func2();} |
分享创造价值,喜欢这个系列文章,不妨关注一下~
Javascript 优化的更多相关文章
- 前端网络、JavaScript优化以及开发小技巧
一.网络优化 YSlow有23条规则,中文可以参考这里.这几十条规则最主要是在做消除或减少不必要的网络延迟,将需要传输的数据压缩至最少. 1)合并压缩CSS.JavaScript.图片,静态资源CDN ...
- 前端性能优化(三)——传统 JavaScript 优化的误区
注:本文是纯技术探讨文,无图无笑点,希望您喜欢 一.前言 软件行业极其缺乏前端人才这是圈内的共识了,某种程度上讲,同等水平前端的工资都要比后端高上不少,而圈内的另一项共识则是--网页是公司的脸面! 几 ...
- 5.JavaScript优化及导航菜单背后的秘密
JavaScript优化及导航菜单背后的秘密 伍星 学习目标1.进一步了解前端优化 学习如何编写良好的 JavaScirpt2.通过导航的学习,了解JavaScirpt的应用 JavaScript在用 ...
- Javascript优化细节:短路表达式
什么是短路表达式? 短路表达式:作为"&&"和"||"操作符的操作数表达式,这些表达式在进行求值时,只要最终的结果已经可以确定是真或假,求值过程 ...
- Javascript 优化项目代码技巧之语言基础(二)
上一篇随笔介绍了如何正确判断对象类型.避免变量污染,特殊值(null.undefined.NaN)的使用,以及其他Javascript中常用关键字与方法的优化,这篇随笔将着重介绍Javascr ...
- Javascript 优化项目代码技巧之语言基础(一)
Javascript的弱类型以及函数作用域等规则使用编写Javascript代码极为容易,但是编写可维护.高质量的代码却变得十分困难,这个系列的文章将总结在项目开发过程中,能够改善代码可读性. ...
- 对JavaScript优化及规范的一些感想
变量...... 1.一个变量只存一种类型的数据,2.尽量减少对隐式转换的依赖,这样可增强程序的可读性,日后修改程序时不至于混乱,3.使用匈牙利命名法,4.使用局部变量时记得加 var 进行声明,不然 ...
- javascript优化--13模式1(DOM和浏览器模式)
注意分离: 通过将CSS关闭来测试页面是否仍然可用,内容是否依然可读: 将JavaScript关闭来测试页面仍然可以执行正常功能:所有连接是否正常工作:所有的表单是否可以正常工作: 不使用内联处理器( ...
- javascript优化
javaScript是一门解释性的语言.它不像java.C#等程序设计语言.由编译器先进行编译再运行.而是直接下载到用户的客户端进行执行.因此代码本身的优劣就直接决定了代码下载的速度以及执行的效率. ...
随机推荐
- 积累的VC编程小技巧之按钮
1.资源种创建的控件,对其属性的动态控制: 在对话框类的头文件里创建所要改变属性的控件的对象,如要改变一个Button(其ID为IDC_MyButton)的属性,则需创建Cbutton的对象m_but ...
- [Android学习笔记]Fragment使用
一.android.app.Fragment 与 android.support.v4.app.Fragment 区别 support.v4.app.Fragment是为了给低版本Android使用的 ...
- python 循环中的else
众多语言中都有if else这对条件选择组合,但是在python中还有更多else使用的地方,比如说循环for,或者while都可以和else组合. 下面简单介绍一下for-else while-el ...
- Python之常用模块(待更新)
模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才 ...
- 函数指针玩得不熟,就不要自称为C语言高手(函数指针是解耦对象关系的最佳利器,还有signal)
记得刚开始工作时,一位高手告诉我说,longjmp和setjmp玩得不熟,就不要自称为C语言高手.当时我半信半疑,为了让自己向高手方向迈进,还是花了一点时间去学习longjmp和setjmp的用法.后 ...
- 如何去掉List中的重复内容
1.通过循环进行删除 public static void removeDuplicate(List list) { ; i < list.size() - ; i ++ ) { ; j > ...
- Python性能分析指南 - 技术翻译 - 开源中国社区
http://www.oschina.net/translate/python-performance-analysis
- 关于使用commons-email包测试发送邮件遇到的问题
项目中有个需求是这样的:客户办理某一项业务,当用户成功提交业务办理信息后,系统生成一个业务随机码给用户,以此作为以后的业务办理结果查询依据.鉴于随机码较长,方便用户记录,在生成随机码的同时,提供用户发 ...
- RSA加密解密和读取公钥、私钥
/// <summary> /// RSA加密解密及RSA签名和验证 /// </summary> public class RSADE { ...
- poj 1220 NUMBER BASE CONVERSION(短除法进制转换)
题目连接:1220 NUMBER BASE CONVERSION 题目大意:给出两个进制oldBase 和newBase, 以及以oldBase进制存在的数.要求将这个oldBase进制的数转换成ne ...