给一个未定义的变量赋值会导致创建一个全局变量,要避免使用全局变量。
== 和 != 操作符会自动执行类型转换。=== 和 !== 操作不会执行任何类型转换,而且在速度上也快于==
[10] === 10 // is false [10] == 10 // is true '10' == 10 // is true '10' === 10 // is false [] == 0 // is true [] === 0 // is false '' == false // is true but true == "a" is false '' === false // is false
结尾使用分号是个好习惯,如果你忘记程序也不会发出警告,因为Javascript已经默认帮助你加上了分号。
即创建后立即执行的函数
(function(){ // some private code that will be executed automatically })(); (function(a,b){ var result = a+b; return result; })(10,20)
arguments虽然是数组的形式,但本身不是数组。
var argArray = Array.prototype.slice.call(arguments);
注:如果toString()方法被重写了,你使用该技巧就得不到想要的结果。 你可以使用:
Array.isArray(obj); // 这是一个新的array的方法
如果你不在使用多重frames的情况下,你还可以使用 instanceof 方法。但如果你有多个上下文,你就会得到错误的结果。
var myFrame = document.createElement('iframe'); document.body.appendChild(myFrame); var myArray = window.frames[window.frames.length-1].Array; var arr = new myArray(a,b,10); // [a,b,10] // instanceof will not work correctly, myArray loses his constructor // constructor is not shared between frames arr instanceof Array; // false
使用 splice 而不要使用 delete 来删除数组中的某个项。使用 delete 只是用 undefined 来替换掉原有的项,并不是真正的从数组中删除。 不要使用:
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 delete items[3]; // return true items.length; // return 11 /* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
而使用:
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 items.splice(3,1) ; items.length; // return 10 /* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
delete 方法应该被用来删除一个对象的某个属性。
跟上面的清空数组的方式类似,我们使用 length 属性来截短一个数组。
var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ]; myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].
如果你将一个数组的 length 设置成一个比现在大的值,那么这个数组的长度就会被改变,会增加新的 undefined 的项补上。 数组的 length 不是一个只读属性。
myArray.length = 10; // the new array length is 10 myArray[myArray.length - 1] ; // undefined
逻辑 AND 还可以被使用来为函数参数设置默认值
Function doSomething(arg1){ Arg1 = arg1 || 10; // arg1 will have 10 as a default value if it’s not already set }
0.1+0.2等于0.30000000000000004。你要知道,所有的JavaScript数字在内部都是以64位二进制表示的浮点数,符合IEEE 754标准。你可以使用 toFixed() 和 toPrecision() 方法解决这个问题。
下面的代码片段能够避免在遍历一个对象属性的时候访问原型的属性
for (var name in object) { if (object.hasOwnProperty(name)) { // do something with name } }
对于jQuery选择器,我们最好缓存这些DOM元素。
var navright = document.querySelector('#right'); var navleft = document.querySelector('#left'); var navup = document.querySelector('#up'); var navdown = document.querySelector('#down');
确保调用 indexOf 时的参数不是负数。
使用 eval 和 Function 构造函数是非常昂贵的操作,因为每次他们都会调用脚本引擎将源代码转换成可执行代码。
var func1 = new Function(functionCode); var func2 = eval(functionCode);
使用 with() 会插入一个全局变量。因此,同名的变量会被覆盖值而引起不必要的麻烦。
不要使用:
var sum = 0; for (var i in arrayNumbers) { sum += arrayNumbers[i]; }
而使用:
var sum = 0; for (var i = 0, len = arrayNumbers.length; i < len; i++) { sum += arrayNumbers[i]; }
好处是,i 和 len 两个变量的取值都只执行了一次,会比下面的方式更高效:
var sum = 0; for (var i = 0; i < arrayNumbers.length; i++) { sum += arrayNumbers[i]; }
因为arrayNumbers.length每次循环的时候都会被计算。
如果你将字符串传递给 setTimeout() 或者 setInterval(),这个字符串将被如使用 eval 一样被解析,这个是非常耗时的。 不要使用:
setInterval('doSomethingPeriodically()', 1000); setTimeOut('doSomethingAfterFiveSeconds()', 5000);
而使用:
setInterval(doSomethingPeriodically, 1000); setTimeOut(doSomethingAfterFiveSeconds, 5000);
在判断情况大于2种的时候,使用 switch/case 更高效,而且更优雅(更易于组织代码)。但在判断的情况超过10种的时候不要使用 switch/case。
在下面的这种情况,使用 switch/case 判断数值范围的时候是合理的
function getCategory(age) { var category = ""; switch (true) { case isNaN(age): category = "not an age"; break; case (age >= 50): category = "Old"; break; case (age <= 20): category = "Baby"; break; default: category = "Young"; break; }; return category; } getCategory(5); // will return "Baby"
一般对于数值范围的判断,用 if/else 会比较合适。 switch/case 更适合对确定数值的判断
写一个函数来创建一个以指定参数作为prototype的对象是有可能
function clone(object) { function OneShotConstructor(){}; OneShotConstructor.prototype= object; return new OneShotConstructor(); } clone(Array).prototype ; // []
在运行时,每次当 catch 从句被执行的时候,被捕获的异常对象会赋值给一个变量,而在 try-catch-finally 结构中,每次都会新建这个变量。 不要使用:
var object = ['foo', 'bar'], i; for (i = 0, len = object.length; i <len; i++) { try { // do something that throws an exception } catch (e) { // handle exception } }
而使用:
var object = ['foo', 'bar'], i; try { for (i = 0, len = object.length; i <len; i++) { // do something that throws an exception } } catch (e) { // handle exception }
在一个XHR请求占用很长时间后(比如由于网络问题),你可能需要中止这次请求,那么你可以对XHR调用配套使用 setTimeout()。
var xhr = new XMLHttpRequest (); xhr.onreadystatechange = function () { if (this.readyState == 4) { clearTimeout(timeout); // do something with response data } } var timeout = setTimeout( function () { xhr.abort(); // call error callback }, 60*1000 /* timeout after a minute */ ); xhr.open('GET', url, true); xhr.send();
此外,一般你应该完全避免同步的Ajax请求。
通常,在一个WebSocket连接创建之后,如果你没有活动的话,服务器会在30秒之后断开(time out)你的连接。防火墙也会在一段时间不活动之后断开连接。
为了防止超时的问题,你可能需要间歇性地向服务器端发送空消息。要这样做的话,你可以在你的代码里添加下面的两个函数:一个用来保持连接,另一个用来取消连接的保持。通过这个技巧,你可以控制超时的问题。 使用一个 timerID:
var timerID = 0; function keepAlive() { var timeout = 15000; if (webSocket.readyState == webSocket.OPEN) { webSocket.send(''); } timerId = setTimeout(keepAlive, timeout); } function cancelKeepAlive() { if (timerId) { cancelTimeout(timerId); } }
keepAlive()方法应该被添加在webSOcket连接的 onOpen() 方法的最后,而 cancelKeepAlive() 添加在 onClose() 方法的最后。
不要使用:
var min = Math.min(a,b); A.push(v);
而使用:
var min = a < b ? a b; A[A.length] = v;