面試-JS基礎知識-作用域和閉包、this

一个甜橙子發表於2024-09-11
  • 函式作為返回值
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 來判斷,並相應處理。

相關文章