当前位置: 首页 > 工具软件 > Lage.js > 使用案例 >

编写高质量javaScript代码笔记

彭弘伟
2023-12-01

编写高质量javaScript代码笔记

一、var散布的问题
JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。当你使用了一个变量,然后不久在函数中又重新声明的话,就可能产生逻辑错误。对于JavaScript,只 要你的变量是在同一个作用域中(同一函数),它都被当做是声明的,即使是它在var声明前使用的时候。看下面这个例子:

//反例
name = "demo";     //全局变量
function getName(){
    alert(name);   //"undefined"
    var name = "DEMO";
    alert(name);   //"DEMO"
}

在这个例子中,你可能会以为第一个alert弹出的是”global”,第二个弹出”loacl”。这种期许是可以理解的,因为在第一个alert 的时候,myname未声明,此时函数肯定很自然而然地看全局变量myname,但是,实际上并不是这么工作的。第一个alert会弹 出”undefined”是因为myname被当做了函数的局部变量(尽管是之后声明的),所有的变量声明当被悬置到函数的顶部了。因此,为了避免这种混 乱,最好是预先声明你想使用的全部变量。

上面的代码片段执行的行为可能就像下面这样:

name = "demo";
function getName(){
    var name;  //等同于 -->var name = undefined
    alert(name);  //"undefined"
    name = "DEMO";
    alert(name);  //"DEMO"
}

二、for循环
我们常用的for循环:

//次佳的循环
for(var i=0;i<array.length;i++){
    //使用array[i]
}

这种形式的循环的不足在于每次循环的时候数组的长度都要去获取,这会降低代码的效率,尤其当array不是数组,而是一个HTMLCollection对象的时候。
HTMLCollections指的是DOM方法返回的对象,例如:

document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()

还有其他一些HTMLCollections,这些是在DOM标准之前引进并且现在还在使用的,有:

document.images;页面上所有的图片元素
document.links;所有a标签元素
document.forms;所有表单
document.forms[0].elements;页面上第一个表单中的所有域

集合的麻烦在于它们实时查询基本文档(HTML页面)。这意味着每次你访问任何集合的长度,你要实时查询DOM,而DOM操作一般都是比较昂贵的。

这就是为什么当你循环获取值时,缓存数组(或集合)的长度是比较好的形式,正如下面代码显示的:

for(var i = 0, max = array.length;i<max;i++){
    //使用array[i]
}

这样,在这个循环过程中,你只检索了一次长度值。
下面提供两种更有效的方式:

//第一种变化的形式
var i, myarray = [];
for (i=myarray.length;i--;){
    //使用myarray[i]做点什么
}
//第二种使用while循环
var myarray = [], i = myaray.length;
while(i--){
    //使用myarray[i]做点什么
}

三、for-in循环
for-in循环应该用在非数组对象的遍历上,使用for-in进行循环也被称为“枚举”。
从技术上讲,你可以使用for-in循环数组,但并不推荐,因为如果数组对象已被自定义的功能增强,就可能发生逻辑错误。另外,在for-in中,属性列表的顺序是不能保证的。所以最好数组使用正常的for循环,对象使用for-in循环。
有个很重要的hasOwnProperty()方法,当遍历对象属性的时候可以过滤掉从原型链上下来的属性。
思考下面一段代码

//对象
var man = {
    hande:2,
    lage:2,
    heade:1
};
//在代码的某个地方
//一个方法添加给了所有对象
if(typeof object.prototype.clone === "undefined"){
    object.prototype.clone = function(){};
}

在这个例子中,我们有一个使用对象字面量定义的名叫man的对象。在man定义完成后的某个地方,在对象原型上增加了一个很有用的名叫 clone()的方法。此原型链是实时的,这就意味着所有的对象自动可以访问新的方法。为了避免枚举man的时候出现clone()方法,你需要应用hasOwnProperty()方法过滤原型属性。如果不做过滤,会导致clone()函数显示出来,在大多数情况下这是不希望出现的。

// 1.
// for-in 循环
for (var i in man) {
   if (man.hasOwnProperty(i)) { // 过滤
      console.log(i, ":", man[i]);
   }
}
/* 控制台显示结果
hands : 2
legs : 2
heads : 1
*/
// 2.
// 反面例子:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
   console.log(i, ":", man[i]);
}
/*
控制台显示结果
hands : 2
legs : 2
heads : 1
clone: function()
*/

四、避免隐式类型转换
JavaScript的变量在比较的时候会隐式类型转换。这就是为什么一些诸如:false == 0 或 “” == 0 返回的结果是true。为避免引起混乱的隐含类型转换,在你比较值和表达式类型的时候始终使用===和!==操作符。

var zero = 0;
if (zero === false) {
   // 不执行,因为zero为0, 而不是false
}

// 反面示例
if (zero == false) {
   // 执行了...
}

五、避免使用eval()
如果你现在的代码中使用了eval(),记住该咒语“eval()是魔鬼”。此方法接受任意的字符串,并当作JavaScript代码来处理。当有 问题的代码是事先知道的(不是运行时确定的),没有理由使用eval()。如果代码是在运行时动态生成,有一个更好的方式不使用eval而达到同样的目 标。例如,用方括号表示法来访问动态属性会更好更简单:
使用eval()也带来了安全隐患,因为被执行的代码(例如从网络来)可能已被篡改。这是个很常见的反面教材,当处理Ajax请求得到的JSON 相应的时候。在这些情况下,最好使用JavaScript内置方法来解析JSON相应,以确保安全和有效。若浏览器不支持JSON.parse(),你可 以使用来自JSON.org的库。比如obj.parseJSON()得到JSON对象,obj.toJSONString()得到JSON字符串。
同样重要的是要记住,给setInterval(), setTimeout()和Function()构造函数传递字符串,大部分情况下,与使用eval()是类似的,因此要避免。在幕后,JavaScript仍需要评估和执行你给程序传递的字符串:

// 反面示例
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// 更好的
setTimeout(myFunc, 1000);
setTimeout(function () {
   myFunc(1, 2, 3);
}, 1000);
 类似资料: