【學習】你不知道的JavaScript + 忍者祕籍 -- 作用域 +閉包 小結
相關知識點
-
編譯語言,動態語言
-
編譯原理:分詞/詞法分析(Tokenizing/Lexing),解析/語法分析(Parsing),程式碼生成。
-
LHS 和 RHS:左查詢和右查詢
LHS:找到變數的容器本身;RHS:找到變數的值 -
引擎:負責整個JavaScript程式的編譯及執行過程
編譯器:負責語法分析及程式碼生成
作用域:負責收集並維護由所有宣告的識別符號(變數)所組成的一系列的查詢,並實施一套非常嚴格的規則,確定當前執行的程式碼對這些識別符號的訪問許可權。 -
詞法作用域 && 動態作用域:JavaScript都是詞法作用域
詞法作用域:定義在詞法階段的作用域,詞法作用域是在寫程式碼時將比那輛和塊作用域寫在哪裡來決定的,因此當詞法分析器處理程式碼時會保持作用域不變(大部分情況下,例如with可改變作用域)。 -
無論函式在哪裡被呼叫,也無論它如何被呼叫,它的詞法作用域都只由函式被宣告時所處的位置決定。
-
eval()和with()會在執行時修改或建立新的作用域,影響JavaScript引擎在編譯階段對作用域查詢進行優化。
-
塊級作用域:從ES3開始,try/catch結構在catch分局中具有塊級作用域;ES6之後引入了if-else for等使用{}包起來的塊級作用域
-
閉包: 通過閉包可以訪問建立閉包時所處環境中的全部變數。閉包為函式建立時所處的作用域中的函式和變數船艦“安全氣泡”,通過這種方式,即使建立函式時所處的作用域已經消失,但是函式仍然能夠獲得執行時所需的全部內容。
-
在JavaScript中,我們可以定義全域性級別,函式級別,塊級別的變數。
-
可以使用關鍵字var,let,const定義變數:
- var定義距離最近的函式級變數或者全域性變數;
- let和const定義距離最近級別(函式或者塊)的變數
- const定義只能賦值一次的變數。
- JavaScript程式碼的執行分成兩個階段進行:一旦建立了新的詞法環境,就會執行第一階段。在第一階段,沒有執行程式碼,但是JavaScript引擎會訪問並註冊在當前詞法環境中所宣告的變數和函式。JavaScript在第一階段完成之後開始執行第二階段,具體如何執行取決於變數的型別(let,var,const和函式宣告)以及環境型別(全域性環境,函式環境,塊級作用域)
具體過程如下:
- 如果時傳經一個函式環境,那麼建立形參及函式引數的預設值。如果是非函式環境,將跳過此步驟。
- 如果是建立全域性或函式環境,就掃描當前程式碼進行函式宣告(不會掃描其他函式的函式體),但是不會掃描函式表示式和箭頭函式。對於找到的函式宣告,將建立函式,並繫結到當前環境與函式名相同的識別符號上。若該識別符號已經存在,那麼該識別符號的值將被重寫。如果是塊級作用域,將跳過此步驟。
- 掃描當前程式碼進行變數宣告,在函式或者全域性環境中,找到所有當前函式以及其他函式之外通過var宣告的變數,並找到所有在其他函式或者程式碼塊之外通過let或const定義的變數。在塊級作用域中,僅查詢當前塊中通過let和const定義的變數。對於所查詢的變數,若該識別符號不存在,進行註冊並將其初始化為undefined。若該識別符號已經存在,將保留其值。
//舉例說明
console.log(typeof fun === 'function') //true: 函式宣告提前第二步,第三步變數宣告提前的時候因為發現識別符號已經存在,則保留原來的值,所以依舊為function
var fun = 3;
console.log(typeof fun === 'number');//true: fun被重新賦值為3
function fun(){};
cosole.log(typeof fun === 'number') //true 在程式實際執行過程中,跳過函式宣告部分。所以依舊為number
進入正題 - 認識閉包
閉包允許函式方位並操作函式外部的變數。只要變數或函式存在於宣告函式時的作用域內,閉包即可使函式能夠訪問這些變數或函式。
//閉包例子
var outerValue = "sss";
var later;
function outerFunc(){
var innerValue = "eee";
function innerFunc(){
console.log(outerValue === "sss")
console.log(innerValue === "eee")
}
later = innerFunc
}
outerFunc();
later(); // true true
說明: 當在外部函式中宣告內部函式時,不僅定義了函式的宣告,而且還建立了一個閉包,該閉包中不僅包含了函式的宣告,還包含了在函式宣告時該作用域中的左右變數。當最終執行內部函式時,儘管宣告時的作用域已經消失了,但是通過閉包,仍然能夠訪問到原始作用域。
注意:雖然閉包時非常有用的,但是不能過度使用。使用閉包時,所有的資訊都會儲存在記憶體中,知道JavaScript引擎確保這些資訊不再使用(可以安全的進行垃圾回收),或頁面解除安裝時,才會清理這些資訊
使用閉包
- 封裝私有變數
function A(){
var value = 55;
this.getValue = function(){
return value
};
this.add = function(){
value = value + 10;
}
}
var a1 = new A();
a1.add();
//a1.value = undefined;
//a1.getValue() = 65
var a2 = new A();
//a2.getValue() = 55;
//注意:
var obj = {};
obj.getValue = a1.getValue ;
//obj.getValue() = 65
注意: 將a1的getValue方法賦給新的obj物件,我們發現可以通過obj.getValue()獲得a1的value值。表明了在JavaScript中沒有真正的私有物件屬性。
- 回撥函式
function move(){
var step = 10;
var sum = 0;
var timer = setInterval(function(){
sum = sum + step;
},1000)
}
相關文章
- javascript忍者祕籍-第五章 閉包和作用域JavaScript
- 閉包:私有化變數 《JavaScript高程3》 《JavaScript忍者祕籍》變數JavaScript
- 溫故而知新篇之《JavaScript忍者秘籍(第二版)》學習總結(三)——閉包和作用域JavaScript
- Javascript-this/作用域/閉包JavaScript
- 你不懂的JS學習筆記(作用域和閉包)JS筆記
- 【譯】學習JavaScript中提升、作用域、閉包的終極指南JavaScript
- JavaScript之作用域和閉包JavaScript
- javascript 基礎(作用域和閉包)JavaScript
- Javascript深入之作用域與閉包JavaScript
- JavaScript物件導向~ 作用域和閉包JavaScript物件
- 閉包作用域
- 你不知道的Javascript(上卷)-作用域筆記JavaScript筆記
- javascript忍者祕籍(第二版)翻譯學習 第一章 JavaScript無處不在JavaScript
- 學習JavaScript作用域JavaScript
- 閉包—-你所不知道的JavaScript系列(4)JavaScript
- [JavaScript閉包]Javascript閉包的判別,作用和示例JavaScript
- 作用域、作用域鏈及閉包(一)
- javascript忍者祕籍-第四章 理解函式呼叫JavaScript函式
- 深入學習作用域和閉包—全面(JS系列之二)JS
- 你不知道的javascript上卷小結JavaScript
- 原型、原型鏈、作用域、作用域鏈、閉包原型
- JS作用域與閉包JS
- JS閉包作用域解析JS
- 我為什麼要推薦《JavaScript 忍者祕籍(第2版)》JavaScript
- javascript忍者祕籍-第六章 生成器與promiseJavaScriptPromise
- JavaScript進階教程(5)-一文讓你搞懂作用域鏈和閉包JavaScript
- JS基礎總結(3)——作用域和閉包JS
- 圖解作用域及閉包圖解
- javascript忍者祕籍(第二版)翻譯學習 第2章 執行時的頁面構建過程JavaScript
- javascript忍者祕籍-第三章 函式定義與引數JavaScript函式
- 【JS基礎】作用域和閉包JS
- 淺談JS作用域、this及閉包JS
- 細讀《你不知道的JavaScript·上卷》1-2 詞法作用域JavaScript
- 讓JS程式碼Level提升的忍者祕籍(實用)JS
- javascript變數物件函式呼叫棧作用域閉包等細解!JavaScript變數物件函式
- JavaScript學習小結JavaScript
- 細讀《你不知道的JavaScript·上卷》1-1 作用域是什麼?JavaScript
- 前端小祕密系列之閉包前端