- 函式作為返回值
function create(){
const a = 100
return function (){
console.log(a) //a在這裡是自由變數,向上尋找
}
}
const fn = create()
const a = 200
fn() //100
- 函式作為引數
function print(fn){
const a = 13
fn()
}
const a = 100
function fn(){
console.log(a)
}
print(fn) //100
*閉包:閉包是指函式“記住”了它被建立時的環境,即使這個函式在它原本的作用域外執行,它依然可以訪問這個環境中的變數.在 JavaScript 中,函式會和它的詞法環境(Lexical Environment)繫結在一起,這就是閉包的本質。
自由變數的查詢是在函式定義的地方向上級作用域查詢,而不是在執行的地方!*
閉包能隱藏資料,不被外界直接訪問。如下👇
function createCounter() {
let count = 0; // 私有變數
return {
increment() {
count++;
console.log(count);
},
decrement() {
count--;
console.log(count);
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 輸出: 1
counter.increment(); // 輸出: 2
console.log(counter.getCount()); // 輸出: 2
counter.decrement(); // 輸出: 1
在上面這個例子中,count 變數只存在於 createCounter 的作用域中,外部無法直接訪問它。increment、decrement 等方法透過閉包的機制,可以持續訪問並修改 count 的值。
this
取什麼值是在函式執行的時候確定的,不是函式定義的時候確定- 箭頭函式的this永遠取上級作用域的值。
- 使用
call(..)
可以確保this指向函式本身
this
實際上是在函式被呼叫時發生的繫結,它指向什麼完全取決於函式在哪裡被呼叫。
總結
下面的i
是全域性變數,對於for
函式內部的i
來說是個自由變數會往上級去找。以至於點選每一個a標籤的時候都彈出來10而不是點選第幾個彈出數字幾。解決辦法:把i
定義到for
內: for(let i = 0)
手寫bind函式第一個繫結的是this
。
bind 的功能是:
- 返回一個新函式。
- 當呼叫新函式時,this 指向指定的物件。
- 可以預置一些引數,呼叫新函式時這些引數自動傳遞給原函式。
注意:
- this要傳進去
- 引數要傳進去
- 返回值要返回回來
下面的arguments
可獲取一個函式的所有的引數,它不是陣列需要將其轉換為陣列形式。
apply第一個引數是this,第二個引數是陣列
手寫bind函式的另外一個寫法:
Function.prototype.myBind = function (context, ...args) {
// 儲存當前函式,即呼叫 bind 的函式
const self = this;
// 返回一個新函式
return function (...newArgs) {
// 將新的引數合併,並透過 apply 呼叫 self
return self.apply(context, [...args, ...newArgs]);
};
};
總結:
bind 函式的實現核心就是透過閉包儲存 this 和引數資訊,並在執行時將它們傳遞給原函式。如果你覺得程式碼有些複雜,建議先理解以下幾個關鍵點:
this 是動態的,可以透過 apply 或 call 方法來改變函式執行時的 this 指向。
閉包可以用來儲存 this 和引數,從而在返回的函式中繼續使用這些值。
new 呼叫的特殊情況需要我們使用 instanceof 來判斷,並相應處理。