众所周知,JavaScript是世界上最流行的变成语言,不管是web网页,手机APP(例如PhoneGap或Appcelerator),还是服务器端(例如NodeJS或Wakanda)还有许多其他的实现。JavaScript也是许多新入门编程的开发人员的首先语言,因为他它不仅可以在web浏览器中显示警告框也能控制一个机器人(使用nodebot或nodruino).那些掌握JavaScript并且能编写有严谨性高性能的代码的开发人员已经成为就业市场最抢手的了。

在这篇文章中,我将分享一组JavaScript提示、技巧和最佳实践,这些应该被所有JavaScript开发人员认识到。不管他们是关于浏览器/引擎或SSJS(服务器端JavaScript)开发人员。

注意,本文中的代码片段在最新的Google Chrome版本测试,它使用V8 JavaScript引擎(V8 3.20.17.15)。

1. 声明变量时,不要忘了var关键字

    给一个未声明的变量赋值时,会自动导致创建一个全局变量。避免全局变量。

2. 使用 === 替代 ==

    在一些情况下 == (或!=)操作符会自动的执行类型转换。===(或!==)操作符不会执行类型转换。它比较值和类型,同事也比==执行速度快。

[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

3. undefined, null, 0, false, NaN, ''(empty string) 均是false

4. 在每行结尾添加分号;

在行尾添加分号是一个非常好的习惯。如果你忘记添加了,也不会被警告,因为在大多数情况下,JavaScript解析器会插入的。关于你为什么应该使用分号的更多细节,可以看看这篇文章。http://davidwalsh.name/javascript-semicolons

5. 创建构造函数

function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
} var Saad = new Person("Saad", "Mousliki");

6. 小心使用typeof, instanceof 和constructor

  • typeof : 一个JavaScript一元运算符。用于返回一个变量的基本类型。typeof null 将会返回"object", 其他的Object类型(包括Array, Date, 还有其他对象类型)也会返回"object".
  • constructor : 返回内部原型属性的属性(呵呵,翻译的好蹩脚哦,原文是is a property of the internal prototype property),可以通过代码覆盖。
  • instanceof : JavaScript操作符。 它用来判断一个变量是否是某个对象的实例。如果是返回true,否则返回false。
var arr = ["a", "b", "c"];
typeof arr; //object
arr instanceof Array; //true
arr.constructor(); //[]

7. 创建闭包(Self-calling)函数

这经常被称为自我调用匿名函数或者即时执行函数表达式(Immediately Invoked Function Expression(IIFE)). 它是一个自动执行的函数,并且有以下格式:

(function(){
// some private code that will be executed automatically
})(); (function(a,b){
var result = a+b;
return result;
})(10,20);

8. 从一个数组中的得到随机数。

var items = [12, 548, 'a', 2, 5478, 'foo', 8852, 'Doe', 2145, 119];
var randomItem = items[Math.floor(Math.random()*items.length)];

9. 在一个特定的范围内得到随机数

这段代码很有用,比如当你试图根据生成的假数据测试项目时,如工资之间的最大值和最小值。

var x = Math.floor(Math.random()*(max-min+1))+min;

10. 生成一组数字从0到最大值的数组

var numbersArray = [], max = 100;
for(var i = 1;numbersArray.push(i++)<max;); //numbers = [1,2,3...100];

11. 生成一组随机的字母数字字符

function generateRandomAlphaNum(len){
var rdmString = "";
for(;rdmString.length < len;rdmString += Math.random().toString(36).substr(2));
return rdmString .substr(0, len);
}

12. 数字数组洗牌

var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
numbers = numbers.sort(function(){return Math.random() - 0.5;})

更好的选择可以通过代码来实现随机排序顺序(例如:Fisher–Yates 洗牌), 然后使用JavaScript原生的sort函数。更多细节可以查看这个讨论

13. 字符串trim函数

在Java,c#, PHP还有其他函数都有经典的trim函数。trim函数时移除字符串的空格,但是JavaScript没有trim函数,所以我们可以把它添加到String对象中。

String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");}; 

原生的trim()函数在最新的JavaScript引擎中已经实现了。

14. 将一个函数附加到另一个函数中。

ar array1 = [12 , "foo" , {name "Joe"} , -2458];

var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 will be equal to [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

15. 将参数对象转换成数组

var argArray = Array.prototype.slice.call(arguments);

16. 验证给定的参数是否是数字

function isNumber(n){
return !isNaN(parseFloat(n)&&isFinite(n));
}

17. 验证给定的参数是否是数组

function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]';
}

记住,如果toString()方法被重写了,你用这段代码将有可能不会得到期望的值。

或者使用。。。

Array.isArray(obj);   // its a new Array method

你也可以使用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

18. 获取数字数组中最大值或最小值

var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(Math, numbers);
var minInNumbers = Math.min.apply(Math, numbers);

19. 置空数组

var myArray = [12, 222, 1000];
myArray.length = 0; // myArray will be equal to []

20. 不要使用删除(delete)或移除(remove)数组中元素

使用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 变成 [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 变成 [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */

delete方法应该用来删除对象属性。

21. 使用数组长度截断数组

和之前置空数组的例子类似,我们使用数组的长度属性来截断数组。

var myArray = [12 , 222 , 1000 , 124 , 98 , 10];
myArray.length = 4; //myArray变成[12, 222, 1000, 124];

作为奖励,如果你设置数组的长度是一个长度大于数组长度的值,那么数组的长度将会改变并且新添加的元素值为undefined。数组长度不是一个可读的属性。

myArray.length = 10; // 新的数组长度是10
myArray[myArray.length - 1] ; // undefined

22. 条件语句使用逻辑AND/OR

var foo = 10;
foo == 10 && doSomething(); //等价于if(foo == 10)doSomething();
foo == 5 || doSomething(); //等价于if(foo != 5) doSomething();

逻辑或也可以用来设置函数参数的默认值。

function doSomething(arg1){
arg1 = arg1 || 10; //arg1 将设为10,如果没有设置的话。
}

23. 使用map()函数来遍历数组元素

var squares = [1,2,3,4].map(function (val) {
return val * val;
});
// squares 变成 [1, 4, 9, 16]

24. 将数组舍入到N个小数的位置

var num =2.443242342;
num = num.toFixed(4); // num 变成 2.4432

记住:toFixed()函数将返回的是一个数组而不是数字。

25. 浮点运算问题

0.1+0.2 === 0.3  // is false
9007199254740992 + 1 // 等于 9007199254740992
9007199254740992 + 2 // 等于 9007199254740994

发生了什么?0.1 +0.2 等于 0.30000000000000004. 你需要知道的是根据IEEE754标准所以JavaScript数值都是内部为64为二进制的浮点数。更多的解释,可以看看这篇博客.

你可以使用toFixed()和 toPrecision()来解决这个问题。

26. 当使用for-in遍历时,检查对象的属性

代码用来避免遍历循环对象原型的属性。

for(var name in obj){
if(object.hasOwnProperty(name)){
// do something with name
}
}

27. 逗号操作符

var a =0;
var b = (a++, 99);
cosole.log(a); // a will be equal to 1
cosole.log(b); // b is equal to 99

28. 缓存变量需要计算或查询

在jQuery选择器中,我们可以缓存DOM元素

var navright = document.querySelector('#right');
var navleft = document.querySelector('#left');
var navup = document.querySelector('#up');
var navdown = document.querySelector('#down');

29. 验证参数之前先使用isFinite()

isFinite(0/0) ; // false
isFinite("foo"); // false
isFinite("10"); // true
isFinite(10); // true
isFinite(undefined); // false
isFinite(); // false
isFinite(null); // true !!!

30.  避免负数索引数组

var numbersArray = [1,2,3,4,5];
var from = numbersArray.indexOf("foo") ; // from等于 -1
numbersArray.splice(from,2); // 返回 [5]

确保传递给splice的参数是非负数。

31. 序列化和反序列化(使用JSON)

var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson 变成 "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString 等于 person 对象 */

32. 避免使用eval()或Function实例

eval或Function实例均是昂贵的操作,由于每次他们要被脚本引擎将源代码转换成执行代码。

var func1 = new Function(functionCode);
var func2 = eval(functionCode);

33. 避免使用with() (好的部分)

使用with()插入一个变量到全局链中。 因此,如果另外一个变量也有同样的名字就会引起混淆同时也会重写这个变量。

34. 避免对数组使用for-in遍历

替换。。。

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的实例化只执行一次,因为它在for循环中是第一个声明。这个比使用下面的快多了。

for (var i = 0; i < arrayNumbers.length; i++)

为什么呢?数组arrayNumbers的长度在每次循环迭代时都有重新计算。

请注意:在每次迭代时重新计算长度的问题在最新的JavaScript引擎已经解决了。

35. 把函数传递给,而不是字符串,给setTimeout()和setInterval()

如果将一个字符串传递给setTimeout()或者setInterval(),字符串会和eval()函数一样被执行,这样速度会变慢。不要这样使用。。。

setInterval('doSomethingPeriodically()', 1000);
setTimeout('doSomethingAfterFiveSeconds()', 5000);

。。。可以这样使用。。。

setInterval(doSomethingPeriodically, 1000);
setTimeout(doSomethingAfterFiveSeconds, 5000);

36.  使用switch/case替换一系列的if/else

当超过2种情况时,使用switch/case更快些,并且它更优雅(更好的组织代码)。当超过10种情况就避免使用它。

37. 用数值范围使用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"

38. 创建一个对象的原型是一个给定的对象

创建一个对象,它的原型是下面给定的参数。。。

function clone(object) {
function OneShotConstructor(){};
OneShotConstructor.prototype= object;
return new OneShotConstructor();
}
clone(Array).prototype ; // []

39. 一个HTML escape函数

function escapeHTML(text) {
var replacements= {"<": "&lt;", ">": "&gt;","&": "&amp;", "\"": "&quot;"};
return text.replace(/[<>&"]/g, function(character) {
return replacements[character];
});
}

40. 在一个循环中避免使用try-catch-finally

try-catch-finally构造函数在运行时在当前链中创建一个新的变量,每次捕获异常时catch子句被执行对象赋给一个变量。

不要这样使用。。。

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
}

41. 对XMLHttpRequests设置超时

如果XHR花费很长时间,你可以终止连接(例如,由于network问题),通过以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 /* 一分钟后超时 */ );
xhr.open('GET', url, true); xhr.send();

作为奖励,通常你应该完全避免XHR同步调用。

42. 处理WebSocket超时

一般在建立WebSocket连接时,服务器会在空闲后30秒暂停你的连接。防火墙也可能在经过一段空闲时间暂停你的连接。

为了处理超时的问题,你可以定期向服务器发送空消息。做到这点,需要把这两个函数添加到你的代码里:一个保持连接,一个取消连接。使用这种方法,你将控制超时。

添加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()方法的末尾。

43. 记住原生操作比函数调用更快. 使用VanillaJS

For example, instead of using…

var min = Math.min(a,b);
A.push(v);
…use… var min = a < b ? a : b;
A[A.length] = v;

44. 不要忘记在编程时使用代码美化器。 在正式使用前使用JSLint 和minification (JSMin, 例如) .

45. JavaScript是极好的:Best Resources To Learn JavaScript

结论

我知道还有很多技巧,窍门和最佳实践,所以如果你有任何添加的或那些我已经共享如果您有任何反馈或修正,请在评论中添加。

参考文献

在本文中,我使用我自己的代码片段,还有一些片段的灵感来自其他文章和论坛。

译文:45 Useful JavaScript Tips, Tricks and Best Practices

翻译不对的地方,欢迎指正。

45个有用的JavaScript技巧的更多相关文章

  1. 12个非常有用的JavaScript技巧

    在这篇文章中,我将分享12个非常有用的JavaScript技巧.这些技巧可以帮助你减少并优化代码. 1) 使用!!将变量转换成布尔类型 有时,我们需要检查一些变量是否存在,或者它是否具有有效值,从而将 ...

  2. 【转】45个实用的JavaScript技巧、窍门和最佳实践

    原文:https://colobu.com/2014/09/23/45-Useful-JavaScript-Tips,-Tricks-and-Best-Practices/ 目录 [−] 列表 第一次 ...

  3. 45 Useful JavaScript Tips, Tricks and Best Practices(有用的JavaScript技巧,技巧和最佳实践)

    As you know, JavaScript is the number one programming language in the world, the language of the web ...

  4. 45个实用的JavaScript技巧、窍门和最佳实践

    在这篇文章中,我将分享一组JavaScript的技巧.窍门和最佳实践,这些都是JavaScript程序员应该知晓的,不管他们是使用在浏览器/引擎上,还是服务器端(SSJS——Service Side ...

  5. 【转】网上看到的“12个非常有用的JavaScript技巧”

    1) 使用!!将变量转换成布尔类型 有时,我们需要检查一些变量是否存在,或者它是否具有有效值,从而将它们的值视为true.对于做这样的检查,你可以使用!!(双重否定运算符),它能自动将任何类型的数据转 ...

  6. [技术翻译]您应该知道的13个有用的JavaScript数组技巧

    本次预计翻译三篇文章如下: 01.[译]9个可以让你在2020年成为前端专家的项目 02.[译]预加载响应式图像,从Chrome 73开始实现 03.[译]您应该知道的13个有用的JavaScript ...

  7. Javascript技巧

    Javascript数组转换为CSV格式 首先考虑如下的应用场景,有一个Javscript的字符型(或者数值型)数组,现在需要转换为以逗号分割的CSV格式文件.则我们可以使用如下的小技巧,代码如下: ...

  8. JavaScript技巧[转载]

    在这篇文章中将给大家分享12个有关于JavaScript的小技巧.这些小技巧可能在你的实际工作中或许能帮助你解决一些问题. 使用!!操作符转换布尔值 有时候我们需要对一个变量查检其是否存在或者检查值是 ...

  9. 12个JavaScript技巧

    转自:http://web.jobbole.com/86146/ 在这篇文章中将给大家分享12个有关于JavaScript的小技巧.这些小技巧可能在你的实际工作中或许能帮助你解决一些问题. 使用!!操 ...

随机推荐

  1. css hack 笔记

    body{background-color:#000\9;}/*ie*/ body{background-color:#0f0\9\0;}/*ie9及以上*/ body{background-colo ...

  2. Mysql 事务隔离级别(图文详解)

    本文由 SnailClimb 和 BugSpeak 共同完成. 事务隔离级别(图文详解) 什么是事务? 事物的特性(ACID) 并发事务带来的问题 事务隔离级别 实际情况演示 脏读(读未提交) 避免脏 ...

  3. 谈PHP中的钩子

    钩子,英文为hooks.在程序中应用相当广泛,但是究竟什么是钩子呢?本人介绍一下目前本人对钩子的理解和相关心得. 假如有这么一段程序流: function fun(){ funA(); funB(); ...

  4. nginx实现防盗链

    有时候在浏览网页的时候,会遇到某些文件(图片等)无法访问的情况,这是因为图片的所有方做了防盗链机制 了解防盗链之前先了解下http referer这个属性,http referer是请求头中的一部分, ...

  5. 用好js与nodejs中的try...catch

    对异常的捕获和处理是提高程序鲁棒性的一个重要方式,即使在javascript/nodejs等看似“很难写出bug”的弱类型语言里,异常捕获处理仍至关重要,这主要是因为: 1.在一个代码块里,如果程序运 ...

  6. Linux下环境搭建(一)——java、tomcat配置

    通过2个周末小憩的时间,终究是把linux环境下的jenkins+gitlab+jmeter框架给弄好了.jenkins的配置系列文章,可以翻看我以前的博文.此次,就将在linux下搭建环境的过程以博 ...

  7. Android使用MediaRecorder和Camera实现视频录制及播放功能整理

    转载请注明出处:http://blog.csdn.net/woshizisezise/article/details/51878566 这两天产品经理向我丢来一个新需求,需要在项目里添加一个视频录制的 ...

  8. 解决 FusionCharts3.2.1 首页无法载入的问题

    在实际项目中测试FusionCharts3.2.1时,发现首次载入无法正常载入,第二次载入就恢复正常!   原因:FusionCharts ID与变量名重复   以下是正常写法: var member ...

  9. Linux的安装与配置

    PS:本文适合刚刚了解Linux系统,并想要学习Linux系统的一些基本操作的同学.只要按如下方法安装配置好,就可以在自己的电脑上使用Linux系统了. 一.安装前的准备 1.下载并安装VMware ...

  10. JS 操作对象 事件 样式

    1.获取标记对象 css 1 - class 2 - id 3 - 标记选择器 js 1 - class 2 - id 3 - 标记 4 - name + document.getElementByI ...