第06章 避免使用全局变量(未完)
“全局对象”是一个神秘的对象,它表示了脚本的最外层上下文。
在浏览器中,window对象往往重载并等同于全局变量,因此任何在全局作用域中声明的变量和函数都是window对象的属性,比如:
var color = "red";
function sayColor() {
console.log(color);
}
console.log(window.color); // "red"
console.log(typeof window.sayColor); // "function"
这段代码定义了全局变量color和全局函数sayColor(),两者都是window对象的属性,尽管我们并没有显式的执行给window对象挂载属性的操作。
6.1 全局变量带来的问题
一般来讲,创建全局变量被认为是最为糟糕的实践,尤其是在团队开发的大背景下。全局变量越多,引入错误的概率将会变得越来越高。
6.1.1 命名冲突
当脚本中的全局变量和全局函数越来越多时,发生命名冲突的概率也会随之增高。
6.1.2 代码的脆弱性
一个依赖于全局变量得到函数是深耦合于上下文环境中的。如果环境发生改变,函数很可能就失效了。
定义 函数时,最好尽可能多地将数据置于局部作用域内,在函数内定义的任何“东西”都应当采用这种写法。任何来自函数外部的数据都应当以参数的形式传进来。这样做可以将函数和其外部环境隔离开来,并且你的修改不会对程序其他部分造成影响。
6.1.3 难以测试
确保你的函数不会对全局变量有依赖,这将增强你的代码的可测试性。当然,你的函数可能会依赖原生的(native)JavaScript全局变量,比如Date、Array等。它们是全局环境的一部分,是和JavaScript引擎相关的,你的函数总是会用到这些全局对象。总之,为了保证你的代码具有最佳的可测试性,不要让函数对全局变量有依赖。
6.2 意外的全局变量
JavaScript陷阱之一:不小心创建全局变量。当你给一个未被 var 语句声明过的变量赋值时,JavaScript会自动创建一个全局变量:
function doSomething(){
var count = 10; // 错误的写成分号
title = "this is a bad idea"; // 不好的写法,创建了全局变量
}
doSomething();
console.log(title); // 能够输出 因为 这里的 title 是一个全局变量
console.log(count); // 报错
最好的规则就是总是使用 var 来定义变量,哪怕是定义全局变量。这样做能大大降低某些场景里省略 var 所导致错误的可能性。
避免意外的全局变量
当你不小心创建了全局变量时,JavaScript并不会报任何错误。这时就需要诸如JSLint和JSHint 的工具了。如果你给一个未声明的变量赋值,这两个工具都会报警告。
6.3 单全局变量方式
依赖尽可能少的全局变量,即只创建一个全局变量。
单全局变量模式已经在各种流行的JavaScript类库中广泛使用。
- YUI定义了唯一一个YUI全局对象。
- jQuery定义了两个全局对象,$和jQuery。
- Dojo定义了一个dojo全局对象。
“单全局变量”的意思是所创建的这个唯一全局对象名士独一无二的(不会和内置API产生冲突),并将你所有的功能代码都挂载到这个全局对象上。比如,假设我想让一个对象表示本书的一章,代码看起来会像下面这样:
function Book(title) {
"use strict";
this.title = title;
this.page = 1;
}
Book.prototype.trunPage = function (direction) {
"use strict";
this.page += direction;
};
var Chapter1 = new Book("第一章");
var Chapter2 = new Book("第二章");
var Chapter3 = new Book("第三章");
这段代码创建了4个全局对象:Book,Chapter1,Chapter2,Chapter3。单全局变量则只会创建一个全局对象,并将这些对象都赋值为它的属性。
var MaintinableJS = {};
MaintinableJS.Book = function (title) {
"use strict";
this.title = title;
this.page = 1;
};
MaintinableJS.Book.prototype.trunPage = function (direction) {
"use strict";
this.page += direction;
};
MaintinableJS.Chapter1 = new MaintinableJS.Book("第一章");
MaintinableJS.Chapter2 = new MaintinableJS.Book("第二章");
MaintinableJS.Chapter3 = new MaintinableJS.Book("第三章");
这段代码只有一个全局变量,即MaintinableJS,其他任何信息都挂载到这个对象上。因为团队的每个人都知道这个全局对象,因此很容易做到继续为它添加属性以避免全局污染。
网友评论