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

資訊專欄INFORMATION COLUMN

JavaScript中作用域相關的那些點

coolpail / 1820人閱讀

摘要:本文為你不知道的上卷中關于作用域相關的知識點的總結(jié)。第一層代表當前作用域,大樓的頂層代表全局作用域。如果一定要找一個點與動態(tài)詞法作用域扯上關系的話,那就是值了。

本文為《你不知道的JavaScript(上卷)》中關于作用域相關的知識點的總結(jié)。

作用域 賦值操作

變量的賦值操作實際上有兩個動作,首先編譯器會在當前作用域中聲明一個變量(如果之前沒有聲明過),然后在運行時引擎會在作用域中查找該變量,如果能夠找到就對它進行賦值。

LHS以及RHS

在運行時引擎會在作用域中查找該變量

引擎對變量所做的查找分為LHS查詢以及RHS查詢LR分別代表一個賦值操作的左側(cè)以及右側(cè)。

講的稍微精確一點:RHS查詢與簡單地查找某個變量的值別無二致,而LHS則是試圖查找到變量的容器本身,從而對其進行賦值。

RHS可以理解成retrieve his source value(取到其源值),這意味著“得到某某的源值”。

深入一點:

console.log(a);

上訴代碼對于a的引用就是一個RHS引用,即查找然后取到a的值。

相比之下,

a = 2;

這里的a就是一個RHS引用。

我們可以簡單的記憶:

當變量出現(xiàn)在賦值操作的左側(cè)時進行LHS查詢,出現(xiàn)在賦值操作的右側(cè)時進行RHS查詢.

注意:作用域查找會在找到第一個匹配的標識符時停止

作用域嵌套

作用域是根據(jù)名稱查找變量的一套規(guī)則

作用域嵌套的定義如下:

當一個塊或者函數(shù)嵌套在另一個塊或函數(shù)中時,就發(fā)生了作用域的嵌套。

理解作用域嵌套這一機制,我們就可以理解變量查找的順序:

在當前作用域查找變量。如果沒有,則進行下一步

判斷是否是全局作用域。如果是,則停止查找過程;如果不是,則進行下一步

進入當前作用域的外層作用域,并進行第一步

形象一點,我們可以把作用域查找想象成在大樓中找人。

第一層代表當前作用域,大樓的頂層代表全局作用域。

首先在當前樓層查找,如果沒有找到,則上一樓進行查找,一直到找到這個人或者找完整個大樓依然沒有找到為止。

異常報錯的種類

如果能將LHS以及RHS進行很好的區(qū)分,那我們就能夠很好的理解瀏覽器所拋出的各種異常。

下舉幾種特別常見的報錯:

ReferenceError:

RHS查詢變量未找到值

嚴格模式LHS查詢失敗

TypeError:

RHS找到該變量值,但嘗試對這個變量的值進行不合理的操作(例如,引用null或者undefined類型的值中的屬性)

詞法作用域

詞法作用域完全由寫代碼期間函數(shù)所聲明的位置來定義

欺騙詞法作用域

注意:欺騙詞法作用域會導致性能下降

eval

eval() 是一個危險的函數(shù), 他執(zhí)行的代碼擁有著執(zhí)行者的權利。如果你運行eval()伴隨著字符串,那么你的代碼可能被惡意方(不懷好意的人)影響, 通過在使用方的機器上使用惡意代碼,可能讓你失去在網(wǎng)頁或者擴展程序上的權限。更重要的是,第三方代碼可以看到作用域在某一個eval()被調(diào)用的時候,這有可能導致一些不同方式的攻擊。相似的Function就是不容易被攻擊的。

with

根據(jù)你所傳遞給它的對象憑空創(chuàng)建了一個全新的詞法作用域

性能問題

欺騙詞法作用域會導致性能下降,其原因在于編譯階段的性能優(yōu)化不起作用。

JavaScript引擎會在即時編譯階段(during the compilation phase)進行數(shù)項的性能優(yōu)化。其中的某些優(yōu)化依賴于能夠根據(jù)代碼的詞法進行靜態(tài)分析,并預先確定所有變量和函數(shù)的定義位置,才能在執(zhí)行的過程中快速找到標識符。

但是,編譯到含有evalwith的代碼時,編譯器無法知道eval或者with會接受什么代碼,自然無法做代碼優(yōu)化。

函數(shù)作用域以及塊作用域

函數(shù)作用域:屬于這個函數(shù)的全部變量都可以在整個函數(shù)的范圍內(nèi)使用及復用(事實上在嵌套的作用域中也可以使用)。

隱藏組件內(nèi)部實現(xiàn)

開發(fā)者最主要是利用函數(shù)作用域?qū)崿F(xiàn)隱藏組件或者API的內(nèi)部實現(xiàn),最小限度的暴露必要內(nèi)容。

比如對于一些組件的開發(fā),大家習慣于利用立即執(zhí)行函數(shù)(function() {})()進行內(nèi)部實現(xiàn)的封裝。

規(guī)避沖突

利用函數(shù)作用域?qū)⒆兞勘3衷谒接小o沖突的作用域中,這樣可以有效規(guī)避掉所有的沖突。

舉個例子,underscore這個庫里面有跟原生js一樣的方法map,那怎么區(qū)分這兩個方法呢?通過將map當做一個屬性掛載在underscore上面,這樣可以避免兩者的沖突。

立即執(zhí)行函數(shù)表達式

形式如下:

(function() {...})()

(function() {...})()

上面兩種形式?jīng)]有區(qū)別,可依個人興趣隨意使用。

立即執(zhí)行函數(shù)表達式的一種進階用法就是把它們當做函數(shù)調(diào)用并傳遞參數(shù)進去。

各種類庫常見的用法是:

(function(global) {
    ...
})(window)
塊作用域

塊作用域目前在ES6中有如下體現(xiàn):

let

const

with:用with從對象創(chuàng)建出的作用域僅在with聲明而非外部作用域中有效。

try/catchcatch分句會創(chuàng)建一個塊作用域,其中聲明的變量僅在catch內(nèi)部有效。

例如:

for (let i; i < 4; i ++) {
    ...
}

console.log(i) // Uncaught ReferenceError: i is not defined
try {
    undefined();
} catch (err) {
    console.log(err);
}

console.log(err); // Uncaught ReferenceError: err is not defined
作用域閉包

知乎上面有關于閉包的問題:什么是閉包?

其中寸志老師的解釋我認為是比較好的。

對于閉包,《你不知道的JavaScript(上卷)》這本書的解釋是:

當函數(shù)可以記住并訪問所在的詞法作用域時,就產(chǎn)生了閉包。

我們實際上來理解閉包時,需要特別注意是兩個點:函數(shù)作用域

簡單的來說,就是函數(shù)以及作用域的結(jié)合,注意,作用域必須是封閉的,其主要的表現(xiàn)形式就是函數(shù)中返回一個函數(shù)。

閉包在類庫、組件封裝中有太多的示例了,本文就不拓展了。

塊作用域與閉包的結(jié)合

首先看一個單純的閉包的代碼:

for (var i = 0; i <= 5; i++) {
    (function() {
       var j = i;
       setTimeout(function timer(){
           console.log(j);
       }, j * 1000) 
    })()
}

這段代碼就是在每次循環(huán)的時候創(chuàng)建一個新的封閉作用域,保存當次循環(huán)的i值。

再看一下下面的代碼:

for (let i = 0; i <= 5; i++) {
    setTimeout(function timer(){
        console.log(i);
    }, i*1000)
}

利用let創(chuàng)建塊作用域,當塊作用域與閉包結(jié)合之后,我們可以減少創(chuàng)建新的封閉作用域這一操作(var j = i);

that"s cool!

動態(tài)詞法作用域

動態(tài)作用域鏈是基于調(diào)用棧的,而不是代碼中的作用域嵌套。

對于JavaScript,不存在動態(tài)作用域。如果一定要找一個點與動態(tài)詞法作用域扯上關系的話,那就是this值了。this值打算在下一篇文章中詳解。

變量提升

舉個最簡單的例子:

alert(a); // undefined
var a = 12;

有同樣作用的是函數(shù)聲明function,例如:

alert(func); // function func(){}
function func() {};

但是函數(shù)表達式不會提升:

foo(); // TypeError

var foo = function bar() {
    ...
}

注意:僅有var和函數(shù)聲明function才可以變量提升。

函數(shù)聲明與函數(shù)表達式的區(qū)別:

區(qū)別函數(shù)聲明和函數(shù)表達式最簡單的方法是看function關鍵字出現(xiàn)在聲明中的位置(不僅僅是一行代碼,而是整個聲明中的位置)。如果function是聲明中的第一個詞,那么就是一個函數(shù)聲明,否則就是一個函數(shù)表達式。

ES6中新增的let以及const關鍵字不可以進行變量提升,我們可以嘗試一下:

// 1. let
alert(a); // Uncaught ReferenceError: a is not defined
let a = "abc";

// 2. const
alert(b); // Uncaught ReferenceError: b is not defined
const b = 123;
函數(shù)優(yōu)先

先來看下面的代碼:

foo(); // 1
var foo;

function foo() {
    console.log(1);
}

foo = function() {
    console.log(2);
}

上面的例子說明:
函數(shù)會被首先提升,然后才是變量

上面的代碼實際等于:

function foo() {
    console.log(1);
}

foo(); // 1

var foo;

foo = function() {
    console.log(2);
}
模塊

模塊這一利器,在以前封裝插件用的非常多,示例如下:

var foo = (function CoolModule() {
    var something = "cool";
    var another = [1, 2, 3];
    
    function doSomething() {
        console.log(something)
    }
    
    function doAnother() {
        console.log(another.join("!"));
    }
    
    return  {
        doSomething: doSomething,
        doAnother: doAnother
    }
})()

模塊模式必備條件如下:

必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會創(chuàng)建一個新的莫模塊實例)。

封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。

當然,說到模塊,我們不得不提到CMD、AMDES6 module等模塊機制了。

知乎上有提到AMD 和 CMD 的區(qū)別有哪些?

我這里簡單提一下兩者的區(qū)別:

AMD:

early executing(提前執(zhí)行)

推薦依賴前置

示例:requireJs

CMD:

as lazy as possible(延遲執(zhí)行)

推薦依賴就近

示例:seaJs

繼續(xù)聊一下ES6的模塊機制(import、export)。

import可以將一個模塊中的一個或多個API導入到當前的作用域中,并分別綁定在一個變量上。

export會將當前模塊的一個標識符(變量、函數(shù))導出為公共API。

Github有很多基于es6實現(xiàn)的代碼功能,請自行查閱。

結(jié)語

好了,作用域相關的點整理完了,我將其中主要分成三部分:

作用域

提升

模塊

如果有遺漏,歡迎指正~

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

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

相關文章

  • 弄懂JavaScript作用和閉包

    摘要:關于本書,我會寫好幾篇讀書筆記用以記錄那些讓我恍然大悟的瞬間,本文是第一篇弄懂的作用域和閉包。作用域也可以看做是一套依據(jù)名稱查找變量的規(guī)則。聲明實際上是根據(jù)你傳遞給它的對象憑空創(chuàng)建了一個全新的詞法作用域。 《你不知道的JavaScript》真的是一本好書,閱讀這本書,我有多次哦,原來是這樣的感覺,以前自以為理解了(其實并非真的理解)的概念,這一次真的理解得更加透徹了。關于本書,我會寫好...

    everfly 評論0 收藏0
  • 關于Cookie那些

    摘要:假設有兩個域名域名域名域名有分級的概念,也就是說域名與域名都是的子域名,又是的子域名在域名所使用的服務中,可以設置域名在服務端設置的時候,設置為或沒有區(qū)別,注意前面的點,即只要是為顯式的聲明,前面帶不帶點沒有區(qū)別。 1 Cookie簡介 Cookie是由W3C組織提出,最早由NetScape社區(qū)發(fā)展的一種機制。Cookie是存儲于訪問者的計算機中的變量。每當同一臺計算機通過瀏覽器請求某...

    sf_wangchong 評論0 收藏0
  • 關于Cookie那些

    摘要:假設有兩個域名域名域名域名有分級的概念,也就是說域名與域名都是的子域名,又是的子域名在域名所使用的服務中,可以設置域名在服務端設置的時候,設置為或沒有區(qū)別,注意前面的點,即只要是為顯式的聲明,前面帶不帶點沒有區(qū)別。 1 Cookie簡介 Cookie是由W3C組織提出,最早由NetScape社區(qū)發(fā)展的一種機制。Cookie是存儲于訪問者的計算機中的變量。每當同一臺計算機通過瀏覽器請求某...

    alogy 評論0 收藏0
  • [譯] 你想知道關于 JavaScript 作用一切

    摘要:原文鏈接原文作者你想知道的關于作用域的一切譯中有許多章節(jié)是關于的但是對于初學者來說甚至是一些有經(jīng)驗的開發(fā)者這些有關作用域的章節(jié)既不直接也不容易理解這篇文章的目的就是為了幫助那些想更深一步學習了解作用域的開發(fā)者尤其是當他們聽到一些關于作用域的 原文鏈接: Everything you wanted to know about JavaScript scope原文作者: Todd Mott...

    Flands 評論0 收藏0
  • 精讀《高性能 javascript

    摘要:嵌套對象成員會造成重大性能影響盡量少用。一般來說你可以通過這種方法提高代碼的性能將經(jīng)常使用的對象成員數(shù)組項和域外變量存入局部變量中。在反復訪問的地方使用局部變量存放引用小心地處理集合因為他們表現(xiàn)出存在性總是對底層文檔重新查詢。 前言 本期我來給大家推薦的書是《高性能JavaScript》,在這本書中我們能夠了解 javascript 開發(fā)過程中的性能瓶頸,如何提升各方面的性能,包括代碼...

    caohaoyu 評論0 收藏0

發(fā)表評論

0條評論

coolpail

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<