您的位置:首页 > Web前端 > JavaScript

(1):编写高质量JavaScript代码的基本要点

2018-04-03 22:47 225 查看

最小全局变量

每个JavaScript环境有一个全局对象,当你在任意的函数外面使用this的时候可以访问到。你创建的每一个全部变量都成了这个全局对象的属 性。在浏览器中,方便起见,该全局对象有个附加属性叫做window,此window(通常)指向该全局对象本身。下面的代码片段显示了如何在浏览器环境 中创建和访问的全局变量:
myglobal = "hello"; // 不推荐写法
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"

全局变量的问题

全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。web页面包含不是该页面开发者所写的代码也是比较常见的,例如:第三方的JavaScript库广告方的脚本代码第三方用户跟踪和分析脚本代码不同类型的小组件,标志和按钮比方说,该第三方脚本定义了一个全局变量,叫做result;接着,在你的函数中也定义一个名为result的全局变量。其结果就是后面的变量覆盖前面的,第三方脚本就一下子嗝屁啦!因此,要想和其他脚本成为好邻居的话,尽可能少的使用全局变量是很重要的。在书中后面提到的一些减少全局变量的策略,例如命名空间模式或是函数立即自动执行,但是要想让全局变量少最重要的还是始终使用var来声明变量。由于JavaScript的两个特征,不自觉地创建出全局变量是出乎意料的容易。首先,你可以甚至不需要声明就可以使用变量;第二,JavaScript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。参考下面的代码:
function sum(x, y) {
// 不推荐写法: 隐式全局变量
result = x + y;
return result;
}
此段代码中的
result
没有声明。代码照样运作正常,但在调用函数后你最后的结果就多一个全局命名空间,这可以是一个问题的根源。经验法则是始终使用var声明变量,正如改进版的sum()函数所演示的:function sum(x, y) {var result = x + y;return result;}

忘记var的副作用(Side Effects When Forgetting var)

隐式全局变量和明确定义的全局变量间有些小的差异,就是通过
delete
操作符让变量未定义的能力。通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过
delete
操作符删除的,而变量是不能的:
// 定义三个全局变量
var global_var = 1;
global_novar = 2; // 反面教材
(function () {
global_fromfunc = 3; // 反面教材
}());

// 试图删除
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true

// 测试该删除
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"
在ES5严格模式下,未声明的变量(如在前面的代码片段中的两个反面教材)工作时会抛出一个错误。

访问全局对象

在浏览器中,全局对象可以通过
window
属性在代码的任何位置访问(除非你做了些比较出格的事情,像是声明了一个名为window的局部变量)。但是在其他环境下,这个方便的属性可能被叫做其他什么东西(甚至在程序中不可用)。如果你需要在没有硬编码的
window
标识符下访问全局对象,你可以在任何层级的函数作用域中做如下操作:var global = (function () {return this;}());这种方法可以随时获得全局对象,因为其在函数中被当做函数调用了(不是通过
new
构造),
this
总 是指向全局对象。实际上这个病不适用于ECMAScript 5严格模式,所以,在严格模式下时,你必须采取不同的形式。例如,你正在开发一个JavaScript库,你可以将你的代码包裹在一个即时函数中,然后从 全局作用域中,传递一个引用指向this作为你即时函数的参数。

单var形式

在函数顶部使用单var语句是比较有用的一种形式,其好处在于:提供了一个单一的地方去寻找功能所需要的所有局部变量防止变量在定义之前使用的逻辑错误帮助你记住声明的全局变量,因此较少了全局变量//zxx:此处我自己是有点晕乎的…少代码(类型啊传值啊单线完成)单var形式长得就像下面这个样子:function func() {var a = 1,b = 2,sum = a + b,myobject = {},i,j;// function body...}您可以使用一个var语句声明多个变量,并以逗号分隔。像这种初始化变量同时初始化值的做法是很好的。这样子可以防止逻辑错误(所有未初始化但声明的变量的初始值是
undefined
)和增加代码的可读性。在你看到代码后,你可以根据初始化的值知道这些变量大致的用途,例如是要当作对象呢还是当作整数来使。你也可以在声明的时候做一些实际的工作,例如前面代码中的
sum = a + b
这个情况,另外一个例子就是当你使用DOM(文档对象模型)引用时,你可以使用单一的var把DOM引用一起指定为局部变量,就如下面代码所示的:function updateElement() {var el = document.getElementById("result"),style = el.style;// 使用el和style干点其他什么事...}

预解析:var散布的问题

JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。当你使用了一个变量,然后不久在函数中又重新声明的话,就可能产生逻辑错误。对于JavaScript,只 要你的变量是在同一个作用域中(同一函数),它都被当做是声明的,即使是它在var声明前使用的时候。看下面这个例子:// 反例myname = "global"; // 全局变量function func() {alert(myname); // "undefined"var myname = "local";alert(myname); // "local"}func();在这个例子中,你可能会以为第一个alert弹出的是”global”,第二个弹出”loacl”。这种期许是可以理解的,因为在第一个alert 的时候,myname未声明,此时函数肯定很自然而然地看全局变量myname,但是,实际上并不是这么工作的。第一个alert会弹 出”undefined”是因为myname被当做了函数的局部变量(尽管是之后声明的),所有的变量声明当被悬置到函数的顶部了。因此,为了避免这种混 乱,最好是预先声明你想使用的全部变量。上面的代码片段执行的行为可能就像下面这样:myname = "global"; // global variablefunction func() {var myname; // 等同于 -> var myname = undefined;alert(myname); // "undefined"myname = "local";alert(myname); // "local"}func();

for循环

for
循环中,你可以循环取得数组或是数组类似对象的值,譬如
arguments
HTMLCollection
对象。HTMLCollection 是一个接口,表示 HTML 元素的集合,它提供了可以遍历列表的方法和属性
arguments
 是一个对应于传递给函数的参数的类数组对象。通常的循环形式如下:for (var i = 0; i < myarray.length; i++) {// 使用myarray[i]做点什么}这种形式的循环的不足在于每次循环的时候数组的长度都要去获取下。这回降低你的代码,尤其当
myarray
不是数组,而是一个
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 = myarray.length; i < max; i++) {// 使用myarray[i]做点什么}这样,在这个循环过程中,你只检索了一次长度值。在所有浏览器下,循环获取内容时缓存
HTMLCollections
的长度是更快的,2倍(Safari3)到190倍(IE7)之间。//zxx:此数据貌似很老,仅供参考注意到,当你明确想要修改循环中的集合的时候(例如,添加更多的DOM元素),你可能更喜欢长度更新而不是常量。伴随着单var形式,你可以把变量从循环中提出来,就像下面这样:function looper() {var i = 0,max,myarray = [];// ...for (i = 0, max = myarray.length; i < max; i++) {// 使用myarray[i]做点什么}}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐