众所周知,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. C#操作Windows用户

    首先需要引入System.DirectoryServices.dll using System; using System.Collections.Generic; using System.Dire ...

  2. Codeigniter CI 框架的一些优化思考

    前段时间使用CI做了两个小项目,对CI的流程和设计理念也有了一些新的认识.CI架构的一些基本优化这里就不做介绍了,如搬离system 文件夹等. 最近有一个稍微大一点的系统,也准备拿CI来做.设计时遇 ...

  3. vue使用props动态传值给子组件里的函数用,每次更新,呼叫函数

    父组件 <template> <div id="app"> <div>详情内容</div> <button v-on:clic ...

  4. Java GUI设置图标

    ImageIcon是Icon接口的一个实现类. ImageIcon类的构造函数: ImageIcon() ImageIcon(String filename)   //本地图片文件 ImageIcon ...

  5. Spring AOP初步总结(二)

    该篇为Spring AOP的一个应用案例:系统日志 需求:将任何删除,更改或新增数据库的操作汇总到数据库中 步骤1:编写切面 @Aspect @Component public class SysLo ...

  6. IE下的圆角

    元素{ position: relative;/*必须*/ z-index: 10;/*必须*/ border-radius: 8px; -moz-border-radius: 8px; -webki ...

  7. cvLoadImage,cvCloneImage的内存泄露问题

    本文转自: http://hi.baidu.com/%C3%A8%D1%DB%D3%E3/blog/item/9d947e1b2b05555742a9adfd.html/cmtid/9872c2260 ...

  8. 学习用5W1H来管理自己的项目/工作

    学习用5W1H来管理自己的项目/工作   最近开始需要系统化的思维模型,这只是一个开始,一下用脑图的形式来简介5W1H的具体内容: 先写xmind思维树的文本导出,后面附上图片.^ _ ^ 5W1H ...

  9. div+css 布局经验 - 最简单的 = 最不变形的(原创技巧)

    站酷几年了 一直饱受其恩泽 尤为感激 一直想奉献些什么 但是苦于水平 苦于奔波 今天静下心来 为大家奉献下 自己的div+css 经验 ,以下观点只代表 深海个人立场 希望为初学者提供一条" ...

  10. CNNs 在图像分割中应用简史: 从R-CNN到Mask R-CNN

    作者:嫩芽33出处:http://www.cnblogs.com/nenya33/p/6756024.html 版权:本文版权归作者和博客园共有 转载:欢迎转载,但未经作者同意,必须保留此段声明:必须 ...