閉包:
一. 原理
1. 概念: 所有對象都是一個閉包; 對象是閉包最大的使用; 閉包只能通過函數調用來產生.(理解不太透)
2. 作用: 延長變量的作用域,使變量能夠在非自身作用域的其他作用域內被使用.
例子: 函數A里的變量a被函數B引用,當函數A被調用完成后,按常理,函數A的上下文環境就出棧被銷毀掉,但是
因為函數B里面引用到了函數A內的變量a(即函數B依賴於函數A中的變量a),且函數B未被執行完,所以函數A的上下文還沒有被銷毀,當函數B也執行完后,那么此時函數A和B的上下文都被釋放掉(即出棧銷毀).
3. 自我理解: 閉包就是作用域和上下文環境相互結合來分析一個作用域內的變量到底是存在於哪一個作用域.
二. 閉包的典型示例
1. 函數作為返回值
function fn1(){
var max = 10;
return function (x) {
if(x > max){
console.log(x);
}
}
}
var fn2 = fn1();
fn2(20);
說明: 1.fn1這個函數的返回值為一個匿名函數function;
2. 當調用fn1()時,用一個變量來接收fn1的返回值;
1. 首先創建全局上下文:
fn1 被聲明並賦值整個函數塊(並確定其內部的匿名函數的自由變量的作用域為fn1作用域;這是自我的理解)
fn2 undefined
2. 執行代碼,給fn2賦值(賦的是fn1的函數塊);
3. 當讀到調用fn1()時,創建fn1這個作用域的上下文環境:
max undefined
4. 執行fn1里面的代碼,給max賦值為10, 並把返回值付給fn2;此時fn1已被調用完,按常理應該出棧被銷毀,但是因為fn1中的max被fn2引用,所以fn1的上下文還沒有被銷毀.
5. fn2接收到返回值后,調用fn2,進入fn2這個函數,在執行fn2的函數體之前,創建fn2的上下文環境;
x(參數) 20
arguments [20]
6. fn2執行完后, fn2的上下文被銷毀,fn1也被銷毀(當fn1里的max被fn2(其他作用域)引用完之后,fn1出棧被銷毀).
2. 函數作為參數
var max = 10;
function fn(x){
if(x > max){
console.log(x);
}
}
//匿名函數,最后的(fn)表示調用這個匿名函數
(function(f){
var max = 100;
f(15);
})(fn);
說明: 1.(function(f){ var max = 100;f(15);})(fn); 這句表示一個匿名函數,(fn)表示調用這個匿名函數;
2.首先創建全局上下文環境(注意:這里就確定了fn函數內的自由變量max的作用域為全局的),之后給全局里的變量賦值,然后執行代碼,當執行到(fn)時,表示調用對應的匿名函數;
3.進入匿名函數,首先創建匿名函數的上下文環境,之后給匿名函數的作用域里的變量賦值,然后執行里面的代碼;
4.當讀到f(15),這句時,進入fn函數,首先創建fn函數的上下文環境,之后給fn函數里的變量賦值,然后執行里面的代碼;
5.當fn函數執行完后,fn的上下文環境銷毀;當匿名函數執行完后,匿名函數的上下文銷毀,最后代碼執行完畢;