博客 / 詳情

返回

説JS作用域,就不得不説説自執行函數

一個兜兜轉轉,從“北深”回到三線城市的小碼農,熱愛生活,熱愛技術,在這裏和大家分享一個技術人員的點點滴滴。歡迎大家關注我的微信公眾號:果凍想

前言

不得不吐槽,學個JS,這個概念也太多了,但是這些概念你不懂吧,代碼你都看不懂,你都寸步難行。好吧,這又遇到了作用域方面的知識盲區,然後發現,又牽扯出了自執行函數。那又能咋整,為了這點破工資,學唄。

適可而止,淺嘗輒止。

JS作用域

作用域指的是一個變量的作用範圍。我們定義的變量它只能在自己的作用域內有效,超出了自己的作用域,變量就不起作用了。但是,JavaScript這門語言很活,如果你不搞懂它的作用域原理,你很可能在不知不覺中被坑了。

在JavaScript中,主要有三種作用域:

  1. 全局作用域:在所有函數外部定義的變量、函數和對象,可以被代碼中的所有部分訪問。
  2. 函數作用域:在函數內部定義的變量、函數和對象,只能在函數內部訪問。
  3. 塊級作用域:在塊級作用域(使用 let 或 const 關鍵字定義的變量)中定義的變量,只能在該塊內訪問。

下面通過不同的示例代碼來演示這幾種作用域,以便更好的理解:

// 全局作用域
var a = "global_var_a";
console.log("全局作用域中訪問:" + a); // 全局作用域中訪問:global_var_a

if (true) {
    console.log("在判斷語句中訪問:" + a); // 在判斷語句中訪問:global_var_a
}

function getA() {
    console.log("在函數中訪問:" + a); // 在函數中訪問:global_var_a
}

getA()

// ==================================================================================
// 函數作用域
var a = "global_var_a";
console.log("全局作用域訪問:" + a); // 全局作用域訪問:global_var_a

if (true) {
    var a = "block_var_a"; // 與全局變量同名
    console.log("在判斷語句中訪問:" + a); // 在判斷語句中訪問:block_var_a
}

function getA() {
    var a = "func_var_a"; // 與全局變量同名
    var b = "func_var_b";
    console.log("在函數中訪問:" + a); // 在函數中訪問:func_var_a
}

getA()
console.log("在全局作用域中訪問:" + a); // 在全局作用域中訪問:block_var_a;由於允許變量重複聲明,導致變量被覆蓋
console.log("在全局作用域中訪問:" + b); // Uncaught ReferenceError: b is not defined

// ==================================================================================
// 塊作用域
var a = "global_var_a";
const b = "global_const_b";

console.log("全局作用域中訪問:" + a); // 全局作用域中訪問:global_var_a
console.log("全局作用域中訪問:" + b); // 全局作用域中訪問:global_const_b

if (true) {
    let a = "block_let_a";
    const b = "block_const_b";
    console.log("在判斷語句中訪問:" + a); // 在判斷語句中訪問:block_let_a
    console.log("在判斷語句中訪問:" + b); // 在判斷語句中訪問:block_const_b
    
    let c = "block_let_c";
    const d = "block_let_d";
}

function getA() {
    let a = "func_let_a";
    const b = "func_const_b";
    console.log("在函數中訪問:" + a); // 在函數中訪問:func_let_a
    console.log("在函數中訪問:" + b); // 在函數中訪問:func_const_b

    let e = "func_let_e";
    const f = "func_const_f";
}

getA()
console.log("全局作用域中訪問:" + a); // 全局作用域中訪問:global_var_a
console.log("全局作用域中訪問:" + b); // 全局作用域中訪問:global_const_b
// console.log("全局作用域中訪問:" + c); Uncaught ReferenceError: c is not defined
// console.log("全局作用域中訪問:" + d); Uncaught ReferenceError: d is not defined
// console.log("全局作用域中訪問:" + e); Uncaught ReferenceError: e is not defined
// console.log("全局作用域中訪問:" + f); Uncaught ReferenceError: f is not defined

這裏順便多説一嘴,關於var定義變量時的變量提升問題,看下面這段代碼:

if (false) {
    var a = "abc";
    console.log(a);
} else {
    console.log(a);
}
console.log(a);

我們執行上面的代碼,理應報Uncaught ReferenceError: a is not defined這個錯誤的,但是由於變量提升問題,這段代碼是不會報錯的,但是邏輯是有問題的。

JS自執行函數

説完JS的作用域問題,再來説説自執行函數。它的定義如下:

自執行函數是指定義後立即執行的函數,它可以被用來創建一個私有作用域。自執行函數的作用域只在函數內部有效,可以用來隱藏變量和函數,避免全局命名衝突,保持代碼的整潔性和可維護性。它可以用來創建私有作用域、實現模塊化、簡化代碼等等,非常靈活和實用。

自執行函數有三種寫法:

(function("參數") {"函數方法";})("給參數傳的值")
(function("參數") {"函數方法";}("給參數傳的值"))
!function("參數") {"函數方法";}("給參數傳的值") // ! 可以換作 void 或其他運算符(比如 +,-,= 等,都能起到立即執行的作用)

因為全局變量很容易引起一些Bug,所以使用自執行函數來實現模塊化,內部變量和函數對外部不可見,只有暴露出去的接口可以被外部訪問。看下面這段代碼。

var myModule = (function(){
    var privateVar ='私有變量';

    function privateFunc(){
        console.log('私有函數');
    }

    return {
        publicFunc: function() {
            console.log('公有函數');
        }
    };
})();

myModule.publicFunc(); // "公有函數"
console.log(myModule.privateVar); // undefined
myModule.privateFunc(); // Uncaught TypeError: myModule.privateFunc is not a function

在上面的代碼中,自執行函數返回一個包含公有函數publicFunc的對象,這個函數可以被外部訪問,而私有變量privateVar和私有函數privateFunc對外部不可見。這樣可以有效地隔離代碼,避免全局變量污染,提高代碼的可維護性和重用性。大部分開元的JavaScript模塊就是以這種方式提供的。

總結

每天一個小知識點,每天進步一點,與君共勉。

一個兜兜轉轉,從“北深”回到三線城市的小碼農,熱愛生活,熱愛技術,在這裏和大家分享一個技術人員的點點滴滴。歡迎大家關注我的微信公眾號:果凍想
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.