成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Effective JavaScript讀書筆記(二)

Yuqi / 1017人閱讀

摘要:盡可能的使用局部變量,少用全局變量。正確的實(shí)現(xiàn)就是在函數(shù)體內(nèi)部使用將聲明成局部變量。在新特性中,引入了塊級(jí)作用域這個(gè)概念,因此還可以使用,來聲明局部變量。它們共享外部變量,并且閉包還可以更新的值。

變量作用域

作用域,對(duì)于JavaScript語言來說無處不在,變量作用域,函數(shù)作用域(運(yùn)行時(shí)上下文和定義時(shí)上下文),作用域污染等等都跟作用域息息相關(guān),掌握J(rèn)avaScript作用于規(guī)則,可以很好地避免一些極端的情況。

盡量少用全局對(duì)象

在JavaScript語言下定義一個(gè)全局對(duì)象或者變量是最容易不過的了,這種全局變量最容易聲明并且使用,因?yàn)樗鼙徽麄€(gè)程序所訪問到,但是經(jīng)驗(yàn)豐富的程序員應(yīng)該盡量避免使用全局變量,它有如下的缺點(diǎn):

全局變量會(huì)污染共享的公共命名空間,可能會(huì)導(dǎo)致意外的命名沖突

全局變量不利于模塊化,它會(huì)導(dǎo)致獨(dú)立組件之間的不必要耦合

但是,也不是說一定禁止使用全局變量,在一些情況下全局變量的使用是不可避免的,例如,它是各個(gè)獨(dú)立組件之間進(jìn)行交互的唯一途徑。

盡可能的使用局部變量,少用全局變量。

局部變量:IIFE,let,cosnt等。

JavaScript的全局命名空間被暴露為在程序全局作用域中可以訪問的全局對(duì)象——window,window對(duì)象作為this關(guān)鍵字的初始值。在web瀏覽器中,全局對(duì)象全部被綁定在全局命名空間,作為window對(duì)象的屬性所使用。
this.foo; // undefined
window.foo; // undefined
var foo = "luffy";//聲明一個(gè)全局變量,會(huì)自動(dòng)綁定到window對(duì)象下
this.foo; // "luffy"
window.foo; // "luffy"
全局對(duì)象的用處——平臺(tái)特性檢測(cè)

可以使用全局對(duì)象來判斷程序是否在瀏覽器環(huán)境下可以運(yùn)行

是否支持地理位置

if(navigator.geolocation){
  //user geolocation
}

是否支持HTML5

if (window.applicationCache) {
    alert("你的瀏覽器支持HTML5");
} else {
    alert("你的瀏覽器不支持HTML5");
}

等等很多種新特性的檢測(cè)。(需要時(shí)請(qǐng)問BD)

始終聲明局部變量
始終使用var來聲明一個(gè)新的局部變量

在JavaScript中,如果不使用var關(guān)鍵字進(jìn)行變量聲明,該變量會(huì)被隱式轉(zhuǎn)換成全局變量,因此會(huì)造成不必要的全局空間污染。

function swap(a,b) {
    temp = a; // temp變成了global
    a = b;
    b = temp;
} 

這段程序沒有使用var來聲明temp變量,最終導(dǎo)致以外的創(chuàng)建了一個(gè)從全局的變量temp,雖然代碼執(zhí)行起來也沒有錯(cuò)誤。正確的實(shí)現(xiàn)就是在函數(shù)體內(nèi)部使用var temp;將temp聲明成局部變量。

在ES6新特性中,引入了塊級(jí)作用域這個(gè)概念,因此還可以使用let,const來聲明局部變量。

避免使用with語句

with語句作用是讓代碼運(yùn)行在特定對(duì)象作用域內(nèi)。with語句是JavaScript最令人詬病的特性,不可靠且效率低下。

總而言之一句話,避免使用with語句即可

熟練掌握閉包

努力掌握J(rèn)avaScript閉包這一概念,對(duì)于前端程序員來說會(huì)有非常大的幫助。理解閉包不用死背概念,理解三個(gè)基本事實(shí)就可以。

JavaScript閉包允許你引用在當(dāng)前函數(shù)以外定義的變量
function outerFoo() {
    var outVar = "外部變量";
    return function() {
        console.log("我在函數(shù)體內(nèi)部,訪問到了:" + outVar);
    }
}
var foo = outerFoo();
foo(); //我在函數(shù)體內(nèi)部,訪問到了:外部變量

上面這個(gè)例子,函數(shù)內(nèi)部返回一個(gè)函數(shù),對(duì)于foo來說,可以訪問到自身外部定義的非全局變量(outVar是outerFoo函數(shù)體內(nèi)的局部變量)。

即使函數(shù)已經(jīng)返回,當(dāng)前函數(shù)仍然可以引用在外部函數(shù)所定義的變量

仍然是上面那個(gè)例子,外部函數(shù)已經(jīng)結(jié)束執(zhí)行過程,返回值賦值給了foo變量(結(jié)果是一個(gè)函數(shù)),現(xiàn)在foo是window作用域下的一個(gè)函數(shù),如圖所示:

可以看到,window下的foo函數(shù)正確的訪問到了outFoo函數(shù)體內(nèi)部的局部變量。

原因:JavaScript的函數(shù)值包含了比調(diào)用它們的時(shí)候執(zhí)行的那部分代碼還要多的信息,也就是說它們還在內(nèi)部存儲(chǔ)了它們可能會(huì)引用的定義在其封閉作用域內(nèi)的變量,這種在其所涵蓋的作用域內(nèi)部跟蹤變量的函數(shù)叫做閉包。

上述的foo函數(shù)就是一個(gè)閉包,其代碼本身引用了外部變量outVar,每一次foo函數(shù)被調(diào)用,都會(huì)引用到這個(gè)outVar變量。
對(duì)于閉包,有一個(gè)很高的評(píng)價(jià):閉包是JavaScript最優(yōu)雅最有表現(xiàn)力的特性之一

閉包可以更新外部變量的值
function box() {
    var val = undefined; //給變量賦值undefined比不給變量賦值要優(yōu)秀
    return {
        set: function(newVal) { val = newVal; },
        get: function() { return val; },
        type: function() { return typeof val }
    }
}
var b = box();
b.type();//"undefined"
b.set(17.2);
b.get();//17.2
b.type();//"number"

上述例子產(chǎn)生了一個(gè)包含三個(gè)閉包的對(duì)象,這三個(gè)閉包分別對(duì)應(yīng)函數(shù)返回對(duì)象的set、get、type屬性。它們共享外部變量val,并且set閉包還可以更新val的值。

實(shí)際上,閉包存儲(chǔ)的是外部變量的引用,而不是它們真實(shí)值的副本.所以閉包是可以更新改變外部變量的值的。

理解變量聲明提升

在ES6,JavaScript開始引入塊級(jí)作用域,使用塊級(jí)作用域聲明的變量只有在包含他們的封閉語句或代碼塊{}內(nèi)部可以使用。但是,在ES6之前,是不存在塊級(jí)作用域的。var聲明的變量會(huì)被綁定到離它聲明最近的那個(gè)作用域上,如果找不到就綁定到最外層window上。

function isWinner(player, others) {
    var higest = 0;
    for(var i = 0, n = others.length; i < n; i++){
        var player = others[i]; //此處重復(fù)聲明了一個(gè)player變量
        if(player.score > higest) {
            higest = player.score;
        }
    }
    return player.score > higest;
}

上述函數(shù)目的是判斷player是否是最高分,但是,在函數(shù)內(nèi)部重復(fù)聲明了player變量,因此,每一次循環(huán)都修改了函數(shù)體的傳入值player變量本身,最終結(jié)果肯定不是預(yù)期的。

在ES5版本,JavaScript的變量作用域概念存在兩種,函數(shù)級(jí)作用域和全局作用域。ES6增加了塊級(jí)作用域,使用let、const可以聲明塊級(jí)作用域變量。

使用立即調(diào)用的函數(shù)表達(dá)式來創(chuàng)建局部作用域

立即執(zhí)行的函數(shù)表達(dá)式(IIFE),是前端面試過程基本都會(huì)問到的問題。下面使用一個(gè)老生常談的面試題來講解它:

 window.onload = function() {
    var result = [];
    for (var i = 0; i < 5; i++) {
        result[i] = function() {
            console.log(i);
        }
    }
    console.log(result[1]());// 5
 }

大家應(yīng)該都知道,最后的執(zhí)行結(jié)果應(yīng)該是5,并且,result數(shù)組內(nèi)部存的值都是5。

造成結(jié)果的原因可以用上面閉包的基本事實(shí)來解釋,內(nèi)部函數(shù)保存的變量其實(shí)是外部變量的引用,也就是說,result的每一個(gè)元素內(nèi)部所引用的i值會(huì)隨著for循環(huán)變化而變化,當(dāng)我們調(diào)用result[1]();這條語句的時(shí)候,i值已經(jīng)變成了5,所以輸出是5。
解決辦法,就是使用立即執(zhí)行函數(shù)來創(chuàng)建一個(gè)局部作用域來解決。

 window.onload = function() {
    var result = [];
    for (var i = 0; i < 5; i++) {
        (function(j) {
            result[j] = function() {
                console.log(j);
            }
        })(i)
    }
    console.log(result[1]());// 1
}

上面使用立即執(zhí)行函數(shù)得到了正確的結(jié)果,原因就是它創(chuàng)建了一段塊級(jí)作用域,立即函數(shù)內(nèi)部將外部變量i的值當(dāng)做參數(shù)穿入內(nèi)部也就是參數(shù)j,之后內(nèi)部使用的一直都是j這個(gè)局部變量,所以就得到了正確的運(yùn)行結(jié)果。

上面IIFE是通過創(chuàng)建一個(gè)塊級(jí)作用域的方式解決的這個(gè)問題,其實(shí)在ES6中,非常簡(jiǎn)便的就可以解決,那就是使用let關(guān)鍵字定義i值,因?yàn)閘et定義的變量就是塊級(jí)作用域變量。for(let i = 0; i < 5l i++)即可得到預(yù)期答案。

在使用IIFE的時(shí)候要注意幾件事:首先,代碼塊不能包含任何跳出塊的break語句和continue語句,因?yàn)樵诤瘮?shù)外部使用break和continue語句是不合法的。其次,如果代碼塊引用了this或特別的arguments變量,IIFE會(huì)改變它們的語義。

當(dāng)心命名函數(shù)表達(dá)式笨拙的作用域

這條規(guī)則對(duì)于現(xiàn)在的環(huán)境和正確使用JavaScript語法規(guī)則編程的程序員來說不太使用,簡(jiǎn)單來說就是下面這種情況。

//推薦使用定義函數(shù)的方式
//第一種:函數(shù)聲明
function double(x) {
    return x*2;
}
//第二種:函數(shù)表達(dá)式
var foo = function(){
    return x*2;
}
//不合理的定義函數(shù)的方式
var f = function three(x) {
    return x*3;
}

千萬不要使用兩種混搭的這種形式,雖然在目前的眾多瀏覽器中都是合法的,但是在低版本終會(huì)存在問題,并且,變量three的作用域只是在自身函數(shù)體內(nèi)部,在其他地方都是不能被引用的,而變量f可以被外部引用 。

當(dāng)心局部塊函數(shù)聲明笨拙的作用域
function foo() {
    return "global";
}

function test(x) {
    function foo() {
        return "local";
    }
    var result = [];
    if (x) {
        result.push(foo());
    }
    result.push(foo());
    return result;
}
test(true); // ["local","local"]
test(false); // ["local"]

這種嵌套函數(shù)聲明的方式也容易出現(xiàn)問題,全局作用域下聲明了函數(shù)foo,在test函數(shù)體內(nèi)部又聲明了一個(gè)foo函數(shù),最后輸出的結(jié)果是函數(shù)體內(nèi)部foo的執(zhí)行結(jié)果。對(duì)于上面這種情況,應(yīng)該在test函數(shù)體內(nèi)部使用函數(shù)表達(dá)式的形式聲明一個(gè)新變量。

function foo() {
    return "global";
}

function test(x) {
    var g = foo;
    var result = [];
    if (x) {
        g = function() {
            return "local";
        }
        result.push(g());
    }
    result.push(g());
    return result;
}
test(true); // ["local","local"]
test(false); // ["global"]
避免使用eval創(chuàng)建局部變量 間接調(diào)用eval函數(shù)優(yōu)于直接調(diào)用

關(guān)于eval函數(shù)理解不是很深,沒太理解這兩節(jié)的內(nèi)容,等有時(shí)間從頭翻翻紅寶書回來再看看。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90067.html

相關(guān)文章

  • Effective JavaScript讀書筆記(一)

    摘要:如果為假值,不傳或者傳入,函數(shù)都會(huì)返回但是,傳入這個(gè)值是完全有可能的,所以這種判斷形勢(shì)是不正確的或者使用來判斷也可以原始類型優(yōu)于封裝類型對(duì)象擁有六個(gè)原始值基本類型布爾值,數(shù)字,字符串,,和對(duì)象。 作為一個(gè)前端新人,多讀書讀好書,夯實(shí)基礎(chǔ)是十分重要的,正如蓋樓房一樣,底層穩(wěn)固了,才能越壘越高。從開始學(xué)習(xí)到現(xiàn)在,基礎(chǔ)的讀了紅寶書《JavaScript高級(jí)程序設(shè)計(jì)》,犀牛書《JavaScri...

    zhoutao 評(píng)論0 收藏0
  • JavaScript模式》讀書筆記()字面量和構(gòu)造函數(shù)

    摘要:對(duì)象字面量定義一個(gè)空對(duì)象這里的空指的是其自身屬性為空,對(duì)象繼承了的屬性和方法添加屬性方法完全刪除屬性方法自定義構(gòu)造函數(shù)用操作符調(diào)用構(gòu)造函數(shù)時(shí),函數(shù)內(nèi)部會(huì)發(fā)發(fā)生以下情況創(chuàng)建一個(gè)新對(duì)象,并且引用了該對(duì)象并繼承了該函數(shù)的原型屬性和方法被加入到的引 對(duì)象字面量 //定義一個(gè)空對(duì)象,這里的空指的是其自身屬性為空,dog對(duì)象繼承了Object.prototype的屬性和方法 var dog={} ...

    _Zhao 評(píng)論0 收藏0
  • JavaScript 語言精粹》 讀書筆記 - 函數(shù)(

    摘要:對(duì)象被傳遞到從句中被捕獲。一些語言提供了尾遞歸優(yōu)化。這意味著如果一個(gè)函數(shù)返回自身遞歸調(diào)用的結(jié)果,那么調(diào)用的過程會(huì)被替換為一個(gè)循環(huán),可以顯著提高速度。構(gòu)建一個(gè)帶尾遞歸的函數(shù)。語言精粹讀書筆記函數(shù) 第四章 函數(shù) Functions (二) 參數(shù) arguments arguments數(shù)組: 函數(shù)可以通過此參數(shù)訪問所有它被調(diào)用時(shí)傳遞給它的參數(shù)列表,包括哪些沒有被分配給函數(shù)聲明時(shí)定義的形式參數(shù)...

    lufficc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<