myfreax

JavaScript 立即调用函数表达式

您将了解 JavaScript 立即调用函数表达式 IIFE

JavaScript 立即调用函数表达式
JavaScript 立即调用函数表达式

在本教程中,您将了解 JavaScript 立即调用函数表达式 IIFE。

长话短说

JavaScript 立即调用函数表达式是一个作为表达式的函数并且创建后立即运行 。下面展示定义了立即调用函数表达式语法:

(function(){
    //...
})();

为什么使用 IIFE

定义函数时,JavaScript 引擎会将函数添加到全局对象。请参阅以下示例:

function add(a,b) {
    return a + b;
}

在 Web 浏览器中,JavaScript 引擎将 add() 函数添加到 window 全局对象:

console.log(window.add);

同样,如果您使用关键词 var 在函数外部声明一个变量,JavaScript 引擎也会将该变量添加到全局对象中:

var counter = 10;
console.log(window.counter); // 10

如果你有很多全局变量和函数,JavaScript 引擎不会释放为它们分配的内存,除非你从全局对象删除变量或者全局对象消失(通常是关闭浏览器标签页)。

因此,脚本可能会低效地使用内存。最重要的是,拥有全局变量和函数可能会导致命名冲突。防止函数和变量污染全局对象的一种方法是使用立即调用的函数表达式。

在 JavaScript ,您可以直接运行以下语句:

'This is a string';
(10+20);

即使表达式无效,此语法也是正确的。函数也可以声明为表达式,称为函数表达式:

let sum = function(a, b) {
    return a + b;
}

在此语法中,赋值运算符 = 右侧的部分是一个函数表达式。因为函数是表达式,所以您可以将它括在括号内:

let sum = (function(a, b) {
    return a + b;
});

在此示例中,sum 变量是接受两个参数的匿名函数。此外,您可以在创建函数后立即运行函数:

let sum = (function(a,b){
    return a + b;
})(10, 20);

console.log(sum);

在此示例中,sum 变量保存匿名函数调用的结果。

以下表达式称为立即调用函数表达式 IIFE,是因为该函数是作为表达式创建并立即执行的:

(function(a,b){
        return a + b;
})(10,20);

这是定义 IIFE 的一般语法:

(function(){
    //...
})();

请注意,您可以使用箭头函数来定义 IIFE:

(() => {
    //...
})();

我们通过将函数变量放在立即调用的函数表达式,可以避免它们污染全局对象:

(function() {
    var counter = 0;

    function add(a, b) {
        return a + b;
    }

    console.log(add(10,20)); // 30
}());

命名 IIFE

IIFE 可以有一个名字。但是,执行后不能再次调用:

(function namedIIFE() {
    //...
})();

以分号 ; 开头的IIFE

有时,您可能会看到以分号 ; 开头的 IIFE:

;(function() {
/* */
})();

在此语法中,分号用于终止语句,以防两个或多个 JavaScript 文件被盲目地连接成一个文件。

例如,您可能有两个文件 lib1.jslib2.js 使用了 IIFE:

(function(){
    // ...
})()


(function(){
    // ...
})()

如果您使用打包工具(webpack,vite等)将两个文件中的代码打包到一个文件,如果没有分号 ;,打包后的 JavaScript 代码将导致语法错误。

IIFE 在行动

假设您有一个名为 calculator.js 的库,其中包含以下函数:

function add(a, b) {
    return a + b;
}

function mutiply(a, b) {
    return a * b;
}
Code language: JavaScript (javascript)

然后将 calculator.js 加载到 HTML 文档中。稍后,您可能还想加载另一个 JavaScript 库 app.js 在同一HTML 文档 :

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>JavaScript IIFE</title>
</head>
<body>
  <script src="calculator.js"></script>
  <script src="app.js"></script>
</body>
</html>

app.js 具有函数 add()

function add() {
    return 'add';
}

当您在 HTML 文档中使用 add() 函数时,它返回字符串 'add' 而不是两个数字的和:

let result = add(10, 20);
console.log(result); // 'add'

这是因为 app.js 库的 add() 函数覆盖 calculator.js 库的 add() 函数。要解决此问题,您可以在 calculator.js 应用 IIFE,如下所示:

const calculator = (function () {
    function add(a, b) {
        return a + b;
    }

    function multiply(a, b) {
        return a * b;
    }
    return {
        add: add,
        multiply: multiply
    }
})();

IIFE 返回一个对象,该对象包含 addmultiply 方法。在 HTML 文档中,您可以按如下方式使用 calculator.js 库:

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>JavaScript IIFE</title>
</head>
<body>
  <script src="js/calculator.js"></script>
  <script src="js/app.js"></script>
  <script>
    let result = calculator.add(10, 20);
    console.log(result); // 30
    console.log(add());
  </script>
</body>
</html>

calculator.add() 调用的是 calculator.js 导出的 add() 函数,而第二次调用的是 app.js 库的  add() 函数。

jQuery 和 IIFE

以下 HTML 文档使用了 jQuery 库:

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>JavaScript IIFE - jQuery</title>
</head>
<body>
  <h1>jQuery Demo</h1>
  <script src="https://code.jquery.com/jquery-3.4.1.slim.js"
    integrity="sha256-BTlTdQO9/fascB1drekrDVkaKd9PkwBymMlHOiG+qLI=" crossorigin="anonymous"></script>
  <script>
    let counter = 1;
    $('h1').click(function () {
      $(this).text('jQuery Demo' + ' Clicked ' + counter++);
    });
  </script>
</body>
</html>

当您导入 jQuery 库时,您可以通过 $jQuery 对象访问许多有用的 jQuery 函数。在幕后,jQuery 使用 IIFE 来公开其函数。

通过这样做,jQuery 只需要使用一个全局变量 $ 来公开大量函数,而不会污染全局对象。

下面的示例说明了如何在 IIFE 中将 jQuery $ 对象更改为 _:

 (function (_) {
      let counter = 1;
      _('h1').click(function () {
        _(this).text('jQuery Demo' + ' Clicked ' + counter++);
      });
  })(jQuery);

在这个例子中,我们将 jQuery 对象传递给 IIFE 并使用_参数代替。

在本教程中,您将了解 JavaScript 立即调用函数表达式 (IIFE) 及其用途。

内容导航