标签:
作者:@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
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 () { /* ... */ } |
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并没有发生改变 |
1
|
0.1 + 0.2 === 0.3 // => false |
1
2
3
4
5
6
7
|
typeof null === ‘null‘ // => false typeof null === ‘object‘ // => true typeof NaN === ‘NaN‘ // => false typeof NaN === ‘number‘ // => true // javascript6个基本类型如下,typeof总是返回这6个值 // number、string、boolean、object、function、undefined // chrome 50中,typeof 3/0 结果为 NaN,有博友知道为什么求告知 |
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" ); } |
1
2
3
4
5
|
typeof NaN === ‘number‘ // => true 类型为number,表示非数字 ‘0.1223‘ // => 0.1223 ‘1e6‘ // => 1000000 ‘1a3‘ // => NaN 1.2 + NaN // => NaN |
1
2
3
4
5
6
7
8
9
10
11
|
// 不能转换为数字的值,均返回true, // 因此并不能用这个函数检测一个值是否真的为 NaN isNaN(NaN) // => true isNaN( ‘abc‘ ) // => true isNaN(0) // => false isNaN( ‘1e6‘ ) // => false isNaN(3/0) // => fasle // NaN是一个唯一自己与自己不相等的值 NaN === NaN // false NaN !== NaN // true |
1
2
3
4
5
6
7
8
|
// 方法一 function _isNaN(value){ return value !== value; } // 方法二 function _isNaN(value) { return typeof value === ‘number‘ && isNaN(value); } |
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
|
// 加一个基本类型判断就OK function isNumber (value) { return typeof value === "number" && isFinite(value); } |
undefined有如下几种情况
(1) 定义了变量但没有赋值 var cc; cc === undefined // => true (2) 获取一个对象不存在的属性 (3) 没有返回值的函数,new + 构造函数除外(4) 定义函数时声明多个形参,调用时传入参数个数少于声明,多余的参数为undefined
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 判断 |
1
2
3
4
5
6
7
8
|
‘‘ == 0 // => true,String与Number,将String转为 Number 0 == ‘0‘ // => true,同上 ‘‘ == ‘0‘ // => false,2个都是字符串,因此直接比较 fasle == ‘0‘ // => true,Boolean与其他,将Boolean转为Number true == ‘3‘ // => false,同上 false == undefined // => false,同上,0与undefined不等 false == ‘false‘ // => false,同上 null == undefined // => true,null与undefined比较返回true |
1
|
typeof value === ‘object‘ && value.constructor === Array |
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; } |
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存在安全问题,任意传入字符串都可能被解析执行,恶意代码也不例外
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 ; } |
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(); } |
分享创造价值,喜欢这个系列文章,不妨关注一下~
标签:
原文地址:http://www.cnblogs.com/Leo_wl/p/5335647.html