函數進階
1當即執行函數表達式編程
當即執行的函數表達式的英文全稱爲Immediately Invoked Function Expression,簡稱就爲IIFE。這是一個如它名字所示的那樣,在定義後就會被當即調用的函數。
使用IIFE來進行初始 化,這樣不會污染到全局環境。
經過IIFE,咱們能夠對咱們的代碼進行分塊。而且塊與塊之間不會互相影響,哪怕有同名的變量 也沒問題,由於IIFE也是函數,在函數內部聲明的變量是一個局部變量
全局做用域是指聲明的變量可在當前環境的任何地方使用。
函數做用域則只能在當前函數所創造的環境中使用。
塊級做用域是指每一個代碼塊也能夠有 本身的做用域。
用var聲明的變量是不存在塊級做用域的,因此即便在if塊中用var聲明變量,它也能在外 部的函數或者全局做用域中使用
解決這個問題有兩種方法,第一:使用ES6中的let關鍵字聲明變量,這樣它就有塊級做用域。 第二:使用IIFE數組
2變量初始化安全
1執行上下文
在ECMAScript中代碼的運行環境分爲如下三種:
・全局級別的代碼:這是默認的代碼運行環境,一旦代碼被載入,JS引擎最早進入的就是這個環境
・函數級別的代碼:當執行一個函數時,運行函數體中的代碼。
・EvaI級別的代碼:在EvaI函數內運行的代碼。
・無論什麼狀況下,只存在一個全局的上下文,該上下文能被任何其它的上下文所訪問到。也 就是說,咱們能夠在test的上下文中訪問到全局上下文中的o ne變量,固然在函數test2或者 test3中一樣能夠訪問到該變量。
・至於函數上下文的個數是沒有任何限制的,每到調用執行一個函數時,引擎就會自動新建出 —個函數上下文,換句話說,就是新建一個局部做用域,能夠在該局部做用域中聲明私有變 量等,在外部的上下文中是沒法直接訪問到該局部做用域內的元素的。
對於執行上下文這個抽象的概念,能夠概括爲如下幾點:
・單線程
· 同步執行
・惟一的一個全局上下文
・函數的執行上下文的個數沒有限制
・每次某個函數被調用,就會有個新的執行上下文爲其建立,即便是調用的自身函數,也是如此。
2函數上下文的創建與激活
每當咱們調用一個函數時,一個新的執行上下文就會被建立出來。然而,在 js引擎的內部,這個上下文的建立過程具體分爲兩個階段,分別是創建階段和代碼執行階段。
創建階段:發生在當調用一個函數,可是在執行函數體內的具體代碼以前
•創建變量對象(arguments對象,形式參數,函數和局部變量)
•初始化做用域鏈
•肯定上下文中this的指向對象
代碼執行階段:發生在具體開始執行函數體內的代碼的時候
•執行函數體內的每一句代碼
咱們將創建階段稱之爲函數上下文的創建,將代碼執行階段稱之爲函數上下文的激活。
變量對象
將整個上下 文看作是一個對象之後獲得的一個詞語。具體來說,咱們能夠將整個函數上下文看作是一個對 象,那麼既然是對象,對象就應該有相應的屬性。對於咱們的執行上下文來講,有以下的三個屬 性:
變量對象,做用域鏈以及this
在函數的創建階段,首先會創建arguments對象。而後肯定形式參數,檢查固然上下文中的函數 聲明,每找到一個函數聲明,就在variableObject下面用函數名創建一個屬性,屬性值就指向該 函數在內存中的地址的一個引用。若是上述函數名已經存在於variableObject(簡稱V0)下面,那 麼對應的屬性值會被新的引用給覆蓋。最後,是肯定當前上下文中的局部變量,若是遇到和函數 名同名的變量,則會忽略該變量。
在創建階段,除了arguments,函數的聲明,以及形式參數被賦予了具體的屬性值 外,其它的變量屬性默認的都是undefinedo而且普通形式聲明的函數的提高是在變量的上面的。
3做用域鏈
所謂做用域鏈,就是內部上下文全部變量對象(包括父變量對象)的列表。此鏈主要是用於變量查 詢。
公式做用域鏈(ScopeChain) = AO + [[scope]]
A0,簡單來講就是VO, AO全稱爲active object(活動對象),對於當前的上下文來說,通常 將其稱之爲A0,對於不是當前的上下文,通常被稱爲V0
[[scope]]:全部父級變量對象的層級列表(也被稱之爲層級鏈)
[[scope]],有一個一個很是重要的特性,那就是[[scope]]是在函數建立的時候,就已經被存 儲了,是靜態的。所謂靜態,就是說永遠不會變,函數能夠永遠不被調用,可是[[scope]]在建立 的時候就已經被寫入了,而且存儲在函數做用域鏈對象裏面。閉包
3閉包異步
1閉包基本介紹
在一個函數的外部,能夠訪問並使用它內部的變量
狹義的閉包
・造成閉包環境的函數可以被外部變量引用,這樣就算它外部上下文銷燬,它依然存在。
・在內部函數中要訪問外部函數的局部變量。
優 點
・經過閉包可讓外部環境訪問到函數內部的局部變量。
・經過閉包可讓局部變量持續保存下來,不隨着它的上下文環境一塊兒銷燬。
2閉包的更多做用
1.封裝變量
閉包能夠幫助把一些不須要暴露在全局的變量封裝成"私有變量"。
2.延續局部變量的壽命
3閉包和麪向對象設計
過程與數據的結合是形容面向對象中的"對象"時常用的表達。對象以屬性的形式包含了數 據,以方法的形式包含了過程。而閉包則是在過程當中以環境的形式包含了數據。一般用面向對象 思想能實現的功能,用閉包也可以實現,反之亦然。函數
4遞歸函數this
遞歸函數是一個一直直接或者間接調用它本身自己,直到知足某個條件纔會退出的函數。spa
let numCalc = function(i){
if(i == 1)
{
return 1;
}
else{
return i * numCalc(i-1);
}
}
console.log(numCalc(4));//24prototype
1•使用遞歸計算從m加到n
let numCalc = function (m, n) {
if (m === n) {
return m;
}
else {
return n + numCalc(m, m > n ? n + 1 : n - 1);
}
}
console.log(numCalc(100, 1));//5050
2•使用遞歸計算出某一位的斐波那契數
let numCalc = function (i) {
if (i == 1) {
return 0;
}
else if (i == 2) {
return 1;線程
else {
return numCalc(i - 1) + numCalc(i - 2); }
} console.log(numCalc(8));//13
3•使用遞歸打印出多維數組裏面的每個數字
let arr = [1, 2, [3, 4, [5, 6], 7, 8], 9, 10]; let test = function (arr) {
for (let i = 0; i < arr.length; i++) { if (typeof arr[i] == 'object') { test(arr[i]);
}
else { console.log(arr[i]);
}
}
};
test(arr);
5高階函數
1高階函數介紹
高階函數(higher-order-function)指的是操做函數的函數,通常有如下兩種狀況:
・函數能夠做爲參數被傳遞
・函數能夠做爲返回值輸出
2參數傳遞
1.回調函數
在Ajax異步請求的應用中,回調函數的使用很是頻繁。想在Ajax請求返回以後作一些事情,但又 並不知道請求返回的確切時間時,最多見的方案就是把回調函數看成參數傳入發起Ajax請求的方 法中,待請求完成以後執行回調函數。
一個函數不適合執行一些請求時,也能夠把這些請求封 裝成一個函數,並把它做爲參數傳遞給另一個函數,"委託"給另一個函數來執行。
2.數組排序
sort()方法 封裝了數組元素的排序方法。把可變的部分封裝在函數參數裏, 動態傳入sor t()方法,使sor t()方法方法成爲了一個很是靈活的方法。
for Each() , map() , eve ry() , some()等函數,也 是常見的回調函數。
3返回值輸出
1.判斷數據的類型
使用 Object,prototype.toString 來計算
Object.prototype.toString.call(obj)返回一個字符串
2. getSingle
4面向切面編程
AOP(面向切面編程)的主要做用是把一些跟核心業務邏輯模塊無關的功能抽離出來,這些跟業務 邏輯無關的功能一般包括日誌統計、安全控制、異常處理等。把這些功能抽離出來以後,再通 過"動態織入"的方式摻入業務邏輯模塊中。這樣作的好處首先是能夠保持業務邏輯模塊的純淨和 高內聚性,其次是能夠很方便地複用日誌統計等功能模塊
在JavaScript中實現AOP, 都是指把一個函數"動態織入"到另一個函數之中。
6高階函數的其餘應用
函數節流(throttle)或函數去抖(debounce),核心其實就是限制某一 個方法的頻繁觸發 1函數防抖 函數防抖的原理是將即將被執行的函數用setTimeout延遲一段時間執行。對於正在執行的函數和 新觸發的函數衝突問題有兩種處理,也分別對應了定時器管理的兩種機制。 第一種是隻要當前函數沒有執行完成,任何新觸發的函數都會被忽略 第二種是隻要有新觸發的函數,就當即中止執行當前函數,轉而執行新函數 下面是一 個比較完整的防抖函數(debounce),該函數接受2個參數,第一個參數爲須要被延遲執行的函 數,第二個參數爲延遲執行的時間 2函數節流 數節流使得連續的函數執行,變爲固定時間段間斷地執行。關於節流的實現,有兩種主流的實 現方式,一種是使用時間戳,一種是設置定時器。 1.使用時間戳 觸發事件時,取出當前的時間戳,而後減去以前的時間戳(最一開始值設爲0),若是大於設置的 時間週期,就執行函數,而後更新時間戳爲當前的時間戳,若是小於,就不執行。 2.使用定時器 觸發事件時,設置一個定時器,再觸發事件的時候,若是定時器存在,就不執行,直到定時器執 行,而後執行函數,清空定時器,這樣就能夠設置下個定時器。