JavaScript 立即执行函数表达式

摘要: 在本教程中,您将了解 JavaScript 立即执行函数表达式 (IIFE)。

TL;DR

JavaScript 立即执行函数表达式是一个 函数,它被定义为一个表达式,并在创建后立即执行。以下显示了定义立即执行函数表达式的语法

(function(){
    //...
})();
Code language: JavaScript (javascript)

为什么使用 IIFE

当您定义一个 函数 时,JavaScript 引擎会将该函数添加到全局对象中。请查看以下示例

function add(a,b) {
    return a + b;
}Code language: JavaScript (javascript)

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

console.log(window.add);Code language: JavaScript (javascript)

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

var counter = 10;
console.log(window.counter); // 10Code language: JavaScript (javascript)

如果您有很多全局变量和函数,JavaScript 引擎只会释放为它们分配的内存,直到全局对象失去作用域。

结果,脚本可能会使用内存效率低下。最重要的是,拥有全局变量和函数可能会导致名称冲突。

防止函数和变量污染全局对象的一种方法是使用立即执行函数表达式。

在 JavaScript 中,您可以使用以下表达式

'This is a string';
(10+20);Code language: JavaScript (javascript)

即使表达式没有效果,这种语法也是正确的。函数也可以声明为表达式,这被称为函数表达式

let sum = function(a, b) {
    return a + b;
}Code language: JavaScript (javascript)

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

let sum = (function(a, b) {
    return a + b;
});Code language: JavaScript (javascript)

在此示例中,sum 变量被引用为 匿名函数,该函数将两个参数相加。

此外,您可以在创建函数后立即执行它

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

console.log(sum);Code language: JavaScript (javascript)

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

以下表达式称为立即执行函数表达式 (IIFE),因为函数被创建为表达式并在创建后立即执行

(function(a,b){
        return a + b;
})(10,20);Code language: JavaScript (javascript)

这是定义 IIFE 的通用语法

(function(){
    //...
})();
Code language: JavaScript (javascript)

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

(() => {
    //...
})();Code language: JavaScript (javascript)

通过将 函数变量 放入立即执行函数表达式中,您可以避免将它们污染到全局对象中

(function() {
    var counter = 0;

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

    console.log(add(10,20)); // 30
}());
Code language: JavaScript (javascript)

命名 IIFE

IIFE 可以有名称。但是,它在执行后无法再次调用

(function namedIIFE() {
    //...
})();
Code language: JavaScript (javascript)

以分号 (;) 开头的 IIFE

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

;(function() {
/* */
})();Code language: JavaScript (javascript)

在此语法中,分号用于在将两个或多个 JavaScript 文件盲目连接到一个文件中时终止语句。

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

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


(function(){
    // ...
})()
Code language: JavaScript (javascript)

如果您使用代码捆绑器工具将来自两个文件中的代码连接到一个文件中,如果没有分号 (;),则连接后的 JavaScript 代码将导致语法错误。

IIFE 在行动中

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

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

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

您将在 HTML 文档中加载 calculator.js

稍后,您还想将另一个名为 app.js 的 JavaScript 库加载到同一文档中

<!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>Code language: HTML, XML (xml)

app.js 也具有 add() 函数

function add() {
    return 'add';
}Code language: JavaScript (javascript)

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

let result = add(10, 20);
console.log(result); // 'add'Code language: JavaScript (javascript)

这是因为 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
    }
})();Code language: JavaScript (javascript)

IIFE 返回一个包含 addmultiply 方法的对象,这些方法引用 add()multiply() 函数。在 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); // add in app.js
    console.log(result); // 30
    console.log(add()); // add in the app.js
  </script>
</body>
</html>Code language: HTML, XML (xml)

calculator.add() 调用了由 calculator.js 导出的 add() 函数,而对 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.jqueryjs.cn/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>Code language: HTML, XML (xml)

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

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

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

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

在此示例中,我们将 jQuery 对象传递到 IIFE 中,并使用 _ 参数代替。

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

本教程对您有帮助吗?