编写可维护的JavaScript---全局变量

一. 全局变量

1. 由全局变量带来的一些问题:

1) 命名冲突
当脚本中的全局变量和全局函数越来越多的时候,发生命名冲突的概率随之增大;如果所有的变量都定义为局部变量,这样的代码最容易维护。

1
2
3
4
5
var color = "red";   // 对color来说绝对不是一个安全的全局变量

function sayName(){
alert( color );
}

2) 代码的脆弱性
一个依赖于全局变量的函数即是深耦合于上下文环境中,如果环境发生改变,函数有可能会失效。
例如上面的代码中color不存在,那么sayName函数就会报错。

所以在定义函数的时候,最好尽可能的将数据置于局部作用域内。任何来自函数外部的数据应当以参数形式传递进来。这样可以将函数和外部环境隔离开。

1
2
3
function sayName( color ){
alert( color );
}

3) 难以测试
如果项目中有很多的全局变量存在,框架要依赖一些全局变量流程才能跑通,那么要进行一些单元测试是很困难的。

2. 意外的全局变量:

当给一个未被var语句声明过的变量赋值时,JavaScript会自动创建一个全局变量:

1
2
3
4
function doSomething(){
var count = 10;
title = "hello world"; // JavaScript会自动创建一个全局变量
}

最好的规则就是总是用var来定义变量,哪怕是定义全局变量。
在严格模式下,未声明变量的赋值操作,JavaScript引擎会报错。

3. 单全局变量方式:

单全局变量:所创建的这个唯一全局对象名是独一无二的,并将所有的功能代码都挂在这个对象上。因此每个可能的全局变量都成了这个唯一全局对象的属性:

1
2
3
4
5
6
7
8
9
var MaintainableJs = {};
MaintainableJs.Book = function ( title ){
this.title = title;
this.page = 1;
}
MaintainableJs.Book.prototype.turnPage = function ( direction ){
this.page += direction;
}
MaintainableJs.Chapter1 = new MaintainableJs.Book( "title" );

即使只有一个全局变量,也存在全局污染的可能性。

1) 命名空间

命名空间是简单的通过全局对象的单一属性表示的功能性分组。
将功能按照命名空间进行分组,可以让你的单全局对象变得井然有序。

创建自己的命名空间:

1
2
3
var MyBooks = {};
MyBooks.MaintainableJavaScript = {}; // 表示这本书的命名空间
MyBooks.HighPerformanceJavaScript = {}; // 表示另外一本书的命名空间

有一种场景是每个文件都需要给一个命名空间挂载东西,可以这样处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var MyGlobal ={
namespace : function (ns){
var parts = ns.split("."),
object = this,
i,
len;

for ( i =0; i < parts.length;i++ ){

if( !object[parts[i]] ){
object[parts[i]] = {};
}
object = object[parts[i]];
}
return object;
}
};

MyGlobal.namespace( "Books.MaintainableJavaScript" ); // 创建一个命名空间
MyGlobal.Books.MaintainableJavaScript.author = "Nicholas C. Zakas"; // 使用命名空间

基于单全局对象使用namespace方法可以让开发者放心的认为命名空间总是存在的。这样每个文件都可以首先调用namespace方法来声明命名空间,这样做也不会对原来存在的命名空间造成任何破坏。

2) 模块
模块是一种通用的功能片段,它并没有创建新的全局变量或命名空间。所有的这些代码都存放在一个表示执行一个任务或发布一个接口的单函数中。

现在最流行的模块: AMD模块 和 YUI 模块;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// AMD    
define("my-books", [ "dependency1", "dependency2" ],
function(dependency1, dependency2) {
var Books = {};
Books.MaintainableJavaScript = {
author: "Nicholas C. Zakas"
};
return Books;
});

// YUI
YUI.add( "my-books", function( Y ){
Y.namespace("Books.MaintainableJavaScript");
Y.Books.MaintainableJavaScript.author = "Nicholas C. Zakas";
}, "1.0.0", {requires:[ "dependency1","dependency2" ]});

4. 零全局变量:

使用前提是内部代码与外部代码无联系。

1
2
3
(function(win) {
var doc = win.document;
})(window)

[参考资料]:
编写可维护的JavaScript,Nicholas C. Zakas 著,李晶 郭凯 张散集 译, Copyright 2012 Nicholas Zakas,978-7-115-31008-8

baishiwen wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!