《JavaScript 模式》读书笔记(2)— 基本技巧2

  前一篇,简朴先容了一些js代码的基本技巧。那么这篇文章,我们继续后续的内容。

一、for循环

  for循环经常用在遍历数组或者类数组工具,如引数(arguments)和HTML容器(HTMLColltion)工具。通常for循环模式使用如下:

for(var i = 0; i < myarray.length; i++) {
    // 对myarray[i]做操作
}

  这种模式的问题在于,每次循环迭代时都要接见数据的长度。这样欠好。以是:

for(var i = 0, max = myarray.length; i < max; i++) {
    // 对myarray[i]做操作
}

  我们可以这样,先把长度存储起来,这样就不会每次循环都要去接见数据的长度了。尤其在一些DOM操作下,接见的速率很慢。

  下面是单变量模式,也可以将变量放到循环以外:

function looper() {
    var i = 0,
        max,
        myarray = [];
    // ...
    for (i = 0,max = myarray.length; i < max; i++){
        //处置myarray[i]
    }
}

  这种模式的利益在于一致性,由于它贯串了单一变量的模式。缺陷在于建立代码时黏贴和复制整个循环对照贫苦。例如,若是要从一个函数复制循环至另一个函数,必须确保能将i和max携带至新函数中(若是这几个量在愿函数中不再需要,则很可能会删除掉它们了)。注重,这里的复制并不是说单纯的复制代码至另一处,而是通过js的代码复用模式在另一个函数中使用。

  对于循环的最后一个改善,时使用i++取代一下两种表达式:

  • i = I + 1
  • i += 1

  for模式重的两个变量引出了一些细微的操作,原因是:

  • 使用了最少的变量(而非最多)
  • 逐步减至0,这样通常更快,由于同0对照比同数组的长度对照,或同非0数组的对照更有用率。

  第一个修改后的模式:

var i ,myarray = [];
for(i = myarray.length; i--;){
    // 处置myarray[i]
}

  第二个使用while循环:

var myarray = [],i = myarray.length;
while(i--){
    //处置myarray[i]
}

  

二、for-in循环

   for-in循环应该用来遍历非数组工具。使用for-in循环也被成为枚举(enumeration)。从技术上来说,可以使用for-in循环来遍历数组(由于在JavaScript中,数组也是工具),然则不推荐这样做,由于当该数组工具已经被自界说函数扩大后,这样做有可能会导致逻辑上的错误。

var myarray = ['a','b','c','d'];
for(var i in myarray) {
    console.log(i)
    console.log(myarray[i])
}

  当遍历工具属性来过滤遇到原型链的属性时,使用hasOwnProperty()方式时非常重要的。好比:

var man = {
    hands:2,
    legs:2,
    heads:1
}

//代码的其他部门
//将一个方式添加到所有工具上
if(typeof Object.prototype.clone === 'undefined'){
    Object.prototype.clone = function () {};
}
// 反模式
for(var i in man) {
    console.log(i + ':' + man[i])
}

  或者,这样才是你想要的:

var man = {
    hands:2,
    legs:2,
    heads:1
}

//代码的其他部门
//将一个方式添加到所有工具上
if(typeof Object.prototype.clone === 'undefined'){
    Object.prototype.clone = function () {};
}

for(var i in man) {
    if(man.hasOwnProperty(i)) {
        console.log(i + ':' + man[i])
    }
}

  那多说一句,Object.hasOwnProperty()方式是干什么的?方式会返回一个布尔值,指示工具自身属性中是否具有指定的属性(也就是,是否有指定的键)。这是MDN上的说法。也就是说,该方式会告诉你,该属性是否是该工具自身的属性,而非其他泉源(好比原型链上的属性)。

  另一种使用hasOwnProperty()的模式是在Object.property中挪用该函数,好比:

for(var i in man) {
    if(Object.prototype.hasOwnProperty.call(man,i)) {
        console.log(i + ':' + man[i])
    }
}

  在使用hasOwnProperty对man工具举行精炼后,可以有用的制止命名冲突,也可以使用一个内陆变量来缓存对照长的属性名,好比:

var i,
    hasOwn = Object.prototype.hasOwnProperty;

for(i in man) {
    if(hasOwn.call(man,i)) {
        console.log(i + ':' + man[i])
    }
}

  注重:严酷来讲,不使用hasOwnProperty()并没有错。依赖于详细任务和对代码的自信,您可以略过该方式并稍微加速循环的执行速率。然则当确认不了工具的内容(和原型链)时,最好照样加上hasOwnProperty()这样的平安检查。

  有一种花样化的变种,然则小我私家极不推荐这样使用,由于:可读性极差,无法通过JSLint检查:

var i,
    hasOwn = Object.prototype.hasOwnProperty;

for(i in man) if(hasOwn.call(man,i)) {
    console.log(i + ':' + man[i])
}

  唯一的优点就是省了一个花括号?

 

三、不要增添内置的原型

  增添组织函数的原型属性是一个增强功效性的壮大的方式,然则有时候该方式会过于壮大。增添内置组织函数(好比Object(),Array(),Function()等)的原型是很有诱惑力的,然则这可能严重影响可维护性,由于这种做法将使代码变得加倍不能展望。

.NET Conf: Xamarin专场会议3.23 开幕

  因此,最好的方式就是不要给内置的原型增添属性,除非:1、未来的ECMAScript版本或JavaScript的详细实现可能将该功效作为一个统一的内置方式时。2、若是检查了自界说的属性或方式并未存在时。或者为了统一差别浏览器或相同浏览器的差别版本而举行的兼容时,条件是要检查是否存在。3、文档纪录,并与团队相同清晰。

  若是确实遇到上面的场景,你可以这样:

if(typeof Object.prototype.myMethod !== 'function'){
    Object.prototype.myMethod = function () {
        // implementation
    }
}

  

四、switch模式

  说到switch,我要多说一句,许多新手都市纠结是if-else性能更好,照样switch性能更好。首先,抛却详细场景谈性能,就是耍流氓。其次,switch在c++这样的语言中,性能确实要稍微好一点。然则,在JavaScript中,两者险些无任何区别,而且switch还可能会引起意外的问题,以是建议使用if-else。

  你若是你确定switch是一个更好的选择,那么你可以这样:

var inspect_me = 0,
    result = '';
switch (inspect) {
case 0:
    result = 'zero';
    break;
case 1:
    result = 'one';
    break;
default:
    result = 'unknow';
    break;
}

  通常,花样是这样的:

  • 使每个case和switch纵向排列整齐(打括号的缩紧是个破例)。
  • 在每个case中使用代码缩进。
  • 在每个case语句末端有个明确的break语句。
  • 制止使用fall-throughs(也就是有意不使用break语句,以使得程序会按顺序一直向下执行)。若是确实希望使用fall-throughs,那么请确信在代码中使用fall-throughs是最好的途径,由于当别人阅读这段代码时会以为这是一个错误。
  • 用default语句来作为switch的竣事:当以上场景都不匹配时,给出一个默认的效果。

 

五、制止使用隐式类型转换

  不要在你的程序中使用==或者!==,请使用===和!===。由于JavaScript在使用对照语句时会执行隐式类型转换。转换的场景可能比你知道的要多得多。

 

六、制止使用eval()

  eval()是个妖怪,它可以实现你的梦想,也可以夺走你的灵魂。以是,请一定制止在你的代码中使用eval()。

  该函数可以将随便字符串看成一个JavaScript代码来执行。当需要讨论的代码是预先就编译好的(不是在动态运行时决议),是没有理由需要使用eval()的。而若是代码是在运行时动态天生的,则也有其他更好的方式来取代eval()实现其功效。好比:

// 反模式
var property = 'name';
alert(eval("obj." + property));

// 推荐的方式
alert(obj[property])

  使用eval()也包罗一些平安隐患,由于这样做有可能执行被篡悔改的代码(例如来自网络的代码)。

  另有一点需要切记的是。通过setInterval(),setTimeout()和function()等组织函数来通报参数,在大部门情形下,会导致类似eval()的隐患,因此应只管制止使用这些函数。在幕后,JavaScript仍然不得不评估和执行以程序代码方式通报过来的字符串:

// 反模式
setTimeout('myFunc()',1000);
setTimeout('myFunc(1,2,3)',1000);

// 推荐的模式
setTimeout(myFunc,1000);
setTimeout(function() {
    myFunc()
},1000)

  使用new Function()组织函数和使用eval()对照类似,因此该函数的使用也需要十分小心,该函数是一个功效壮大的函数,然则通常容易被误用。若是一定需要使用eval(),那么可以思量使用new Function()来取代。这样做的一个潜在利益是由于在new Function()中的代码将在局部函数空间中运行,因此代码中任何接纳var界说的变量不会自动成为全局变量。另一个制止自动成为全局变量的方式是将eval()挪用封装到一个即时函数中。

  看下面的代码,在这里只有un这个变量仍然是一个全局变量,会影响到命名空间:

console.log(typeof un);
console.log(typeof deux);
console.log(typeof trois);

var jsstring = "var un = 1; console.log(un)";
eval(jsstring);

jsstring = "var deux = 2; console.log(deux)";
new Function(jsstring)();

jsstring = "var trois = 3; console.log(trois)";
(function() {
    eval(jsstring);
}());

console.log(typeof un);
console.log(typeof deux);
console.log(typeof trois);

  另一个new Function()和eval()的区别是eval()会影响到作用域链,而Function更多的类似于一个沙盒。无论在那里执行Function,它都仅仅能看到全局作用域。因此对局部变量的影响对照小。下面的例子,eval()可以接见和修改它外部作用域的变量,然而Function不行(请注重使用Function和使用new Function是一样的)。

(function () {
    var local = 1;
    eval("local = 3;console.log(local)");
    console.log(local);
}());

(function() {
    var local = 1;
    Function("console.log(typeof local);")();
}())

 

七、使用parseInt()的数值约定

   通过使用paresInt(),可以从一个字符串中获取数值。该函数的第二个参数是一个克制参数,通常可以忽略该参数,然则最好不要这样做。由于当剖析的字符串是0开头,就会泛起错误:例如在处置日期是只有一部门日期会进入字段。在ECMAScript 3中,0最先的字符串会被看成一个八进制数,而在ECMAScript 5中发生了改变。为了制止不一致性和为预期的效果,请每次都指定详细进制参数:

var month = '06',
    year = '09';
month = parseInt(month,10);
year = parseInt(year,10);
console.log(month,year);

  另一个将字符串转换成数值的方式是:

Number('01');

  这种方式通常会比parseInt()快许多,由于正如其名称一样,parseInt()是剖析而不是简朴的转换。然则若是希望“08 hello”会返回一个数值,那么除了parseInt()之外,其他方式都市失败并返回NaN。

  这篇内容对照多,然则在现实的工作中十分具有价值。下一篇会讨论一些规范和约束,好比命名,打括号,缩进空格等在编码中的处置。

原创文章,作者:28x29新闻网,如若转载,请注明出处:https://www.28x29.com/archives/1654.html