編寫可維護(hù)的JavaScript——全局變量

JavaScript執(zhí)行環(huán)境在很多方面都有其獨(dú)特之處。全局變量和函數(shù)的使用便是其中之一。事實(shí)上,JavaScript的初始執(zhí)行環(huán)境是由多種多樣的全局變量所定義的,這些全局變量在腳本環(huán)境創(chuàng)建之初就已經(jīng)存在了。這些都是掛載在全局對象上的。

在瀏覽器中,window對象往往重載并等同于全局對象,因此任何在全局作用域中聲明的變量和函數(shù)都是window對象的屬性,如下所示,兩者都是window對象的屬性。

var color = 'red';
 
function showColor () {
    alert(color);
}

console.log(window.color);    // 'red'
console.log(typeof window.showColor);    // 'function'

1. 全局變量帶來的問題

一般來講,創(chuàng)建全局變量被認(rèn)為是糟糕的事,尤其是在團(tuán)隊(duì)開發(fā)的大背景下更是如此。

命名沖突: 當(dāng)腳本中的全局變量和全局函數(shù)越來越多時(shí),發(fā)生命名沖突的概率也大為增加。如上代碼所示,當(dāng)全局變量color和全局函數(shù)showColor()在同一個(gè)文件時(shí)還好,但是當(dāng)有很多地方引用全局變量和全局對象時(shí),追蹤起來就變得相當(dāng)麻煩。

代碼脆弱: 一個(gè)依賴于全局變量的函數(shù)即是深耦合于上下文環(huán)境之中,如果環(huán)境發(fā)生改變,函數(shù)很可能就失效了。

意外的全局變量: 當(dāng)你給一個(gè)未被var語句聲明過的變量賦值時(shí),JavaScript就會(huì)自動(dòng)創(chuàng)建一個(gè)全局變量,尤其當(dāng)你無意中創(chuàng)建的全局變量與系統(tǒng)定義的全局變量相同時(shí),會(huì)修改系統(tǒng)的全局變量的值。如下:

function doSomething () {
    var count = 10;
        title = "Maintainable JavaScript";    //  不好的寫法,創(chuàng)建了全局變量
}
2. 解決全局變量帶來的問題
a. 避免意外的全局變量

避免意外的全局變量可以使用JSLint和JSHint等檢測工具來,或者使用JS的嚴(yán)格模式,使用JS的嚴(yán)格模式會(huì)通知JavaScript引擎在運(yùn)行代碼前執(zhí)行更嚴(yán)格的錯(cuò)誤處理和語法檢查。其中一個(gè)規(guī)則可以探測未聲明變量的賦值操作。

b. 單全局變量

單全局變量的含義即只創(chuàng)建一個(gè)全局變量。如JQuery定義了兩個(gè)特定的全局變量,$和jQuery,只有在$被其他類庫使用了的情況下,為了避免沖突,應(yīng)當(dāng)使用jQuery。

“單全局變量” 的意思是所創(chuàng)建的這個(gè)唯一全局對象名是獨(dú)一無二的,并將你所有的功能代碼都掛載到這個(gè)全局對象上。因此每個(gè)可能的全局變量都成為你唯一全局對象的屬性,從而不會(huì)創(chuàng)建多個(gè)全局變量。

c. 命名空間

即使你的代碼只有一個(gè)全局對象,也存在著全局污染的可能性。大多數(shù)使用單全局變量模式的項(xiàng)目同樣包含“命名空間”的概念。命名空間是簡單的通過全局對象的單一屬性表示的功能分組。將功能按照命名空間進(jìn)行分組,可以讓你的全局對象變得井然有序,同時(shí)讓團(tuán)隊(duì)成員能夠知曉新功能應(yīng)該屬于哪個(gè)部分。

現(xiàn)有js中并不支持原生的命名空間。在JS中創(chuàng)建的任何對象都默認(rèn)是全局對象。在現(xiàn)代的大規(guī)模JS開發(fā)中,不采用命名空間會(huì)造成非常糟糕的命名方式,導(dǎo)致代碼丑陋不可讀。當(dāng)引入第三方庫后,更可能會(huì)發(fā)生明明覆蓋的情況。

好消失是:在ES6中,就有了native的命名空間可以用了,但是當(dāng)下我們還需要一些特殊的手段來模擬命名空間的概念。簡單來說,就是創(chuàng)建一個(gè)簡單字面量來打包所有的相關(guān)函數(shù)和變量。這個(gè)簡單的對象字面量模擬了命名空間的作用。

var NAMESPACE = {
    person: funnction(name) {
        this.name = name;
        this.getName = function() {
            return this.name;
        }
    }
}

// 調(diào)用方法
var p = new NAMESPACE.person("andy");
p.getName()

如此一來,我們就可以通過命名空間來聲明多個(gè)person對象了。但是這里還有一個(gè)問題,我們這里使用的是一個(gè)全局對象,在添加這個(gè)“命名空間”的時(shí)候,我們有可能覆蓋全局空間中的同名對象。因此我們需要再聲明命名空間之前進(jìn)行檢查,保證全局空間的安全:

// 在聲明之前進(jìn)行檢查,防止覆蓋全局的同名對象。
var NAMESPACE = NAMESPACE || {};

若全局空間中已經(jīng)有同名對象,則不覆蓋該對象;否則創(chuàng)建一個(gè)新的命名空間。采用了這個(gè)安全地命名空間后,聲明的方法也需要略作改動(dòng):

var NAMESPACE = NAMESPACE || {};

MYNAMESPACE.person = function(name) {
    this.name = name;
};

MYNAMESPACE.person.prototype.getName = function() {
    return this.name;
};

// 使用方法
var p = new MYNAMESPACE.person("ifcode");
p.getName();        // ifcode

注意在定義命名空間構(gòu)造函數(shù)時(shí),需要將其定義在prototype上,否則新建的實(shí)例無法訪問對象的方法。

d. 模塊化

另外一種基于單全局變量的擴(kuò)充方法是模塊,模塊是一種通用的功能片段,它并沒有創(chuàng)建新的全局變量或命名空間。相反,這些代碼都存放于一個(gè)表示執(zhí)行一個(gè)任務(wù)或發(fā)布一個(gè)借口的單函數(shù)中。可以用一個(gè)名稱來表示這個(gè)模塊,同樣這個(gè)模塊可以依賴其他模塊。

e. 零全局變量

這個(gè)種方法應(yīng)用場景不多,只有在特殊場景下才會(huì)應(yīng)用。最常見的情形是一段不會(huì)被其他腳本訪問到的完全獨(dú)立的腳本,之所以存在這種情形,是因?yàn)樗兴璧哪_本都會(huì)合并到一個(gè)文件,或者因?yàn)檫@段非常短小且不提供任何借口的代碼會(huì)被插入至一個(gè)頁面中,最常見的用法是創(chuàng)建一個(gè)書簽。

書簽是獨(dú)立的,他們并不知道頁面中包含什么且不需要頁面知道它的存在。最終我們需要一段“零全局變量”的腳本嵌入到頁面中,實(shí)現(xiàn)方法就是使用一個(gè)立即執(zhí)行的函數(shù)調(diào)用并將所有腳本放置其中,比如“

(function (win)) {
    var doc = win.document;
    
    // 在這里定義其他的變量

    // 其他相關(guān)代碼
}

這段代碼注入到頁面中不會(huì)產(chǎn)生任何的全局變量,之后你可以通過將函數(shù)設(shè)置為嚴(yán)格模式來避免創(chuàng)建全局變量。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運(yùn)行的地址不確定 關(guān)于...
    SeanCST閱讀 8,133評(píng)論 0 27
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,562評(píng)論 0 13
  • 第3章 基本概念 3.1 語法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,514評(píng)論 0 21
  • 打算開始寫每日總結(jié),內(nèi)容包括今天看過的信息、發(fā)生的事、吃喝生活、工作學(xué)習(xí)、人人人感悟。 原因一 復(fù)盤生活 正在...
    midtwo閱讀 260評(píng)論 0 0
  • 全文總目錄 彭磊兩手搓著,有些難為情地說,“我真是擔(dān)心自己管不好,萬一把公司給整垮了,我怎么對得住你呢。再說了,我...
    簡小塵閱讀 352評(píng)論 1 4

友情鏈接更多精彩內(nèi)容