JavaScript 立即执行函数

江湖十年 2021-01-21 16:42:38
函数 javascript 执行 立即


立即执行函数,顾名思义,即创建后被立刻执行的函数。在实际工作中,立即执行函数并不是必须用到的语法,不过使用立即执行函数有个好处是能够简化代码。

立即执行函数语法

在 JavaScript 中一个普通的函数定义语法如下:

function foo() {
console.log(123);
}

如果要调用这个函数,那么我们会执行:

foo();

如果把它改成立即执行函数的写法是这样的:

(function foo() {
console.log(123);
}());

或者这样的:

(function foo() {
console.log(123);
})();

以上两个立即执行函数相当于 函数声明 + 函数调用。一个普通的函数声明需要使用 function 关键字,函数调用需要使用函数名加一个圆括号(foo())。我们知道函数名实际上保存了函数的引用,所以 foo 变量保存了 foo 函数体的引用,因此理论上立即执行函数的写法可以是这样:

function foo() {
console.log(123);
}();

但是如果这样写,JavaScript 解释器会报 SyntaxError 语法错误。所以就需要用一个括号把整个函数括起来再进行调用。用来调用函数的括号可以写在把函数括起来的括号的里面或者外面,两种写法没有任何区别,选择一个你更能接收的写法即可。

立即执行函数特点

立即执行函数和普通函数几乎没什么差别,既能接收参数、也能有返回值,但它们之间还是有一个非常不一样的地方,就是立即执行函数执行完后就立刻被销毁。

我们上面定义了一个 foo 函数,如果想多次执行,那么只需要多次调用 foo() 即可:

function foo() {
console.log(123);
}
foo();
foo();
foo();

但是,如果是立即执行函数,多次调用 foo() 将得到异常。

(function foo() {
console.log(123);
})();
foo(); // ReferenceError: foo is not defined

可以看到在第二次调用 foo() 函数时,会得到 foo is not defined。即 foo 函数实际上已经被销毁了。所以我们在定义立即执行函数的时候,通常不需要指定函数名,定义一个匿名函数即可:

(function () {
console.log(123);
})();

立即执行函数使用场景

立即执行函数执行一次就被销毁,所以如果我们定义了一个函数只被执行一次的时候就可以将其换成立即执行函数。

立即执行函数比较常见的两个使用场景是:

  1. 数据初始化
  2. 解决闭包中引用循环变量的问题

对于数据初始化比较好理解,如想要计算 num 的值:

var num = (function (a, b) {
return a + b;
})(1, 2);

而对于如何解决闭包中引用循环变量的问题,我们需要看一个稍微复杂一点的例子:

function foo() {
var arr = [];
for (var i = 0; i < 3; i++) {
arr.push(function bar() {
return i * i;
});
}
return arr;
}
var result = foo();
result[0](); // 9
result[1](); // 9
result[2](); // 9

以上示例代码中,闭包中的 bar 函数引用了其外部的循环变量 i,我们本来期待的结果是 014,但实际上最终结果都为 9

出现此问题的原因是 for 循环不具备独立的块级作用域导致的,此时就可以使用立即执行函数来解决这个问题。

function foo() {
var arr = [];
for (var i = 0; i < 3; i++) {
arr.push((function (j) {
return function bar() {
return j * j;
}
})(i));
}
return arr;
}
var result = foo();
result[0](); // 0
result[1](); // 1
result[2](); // 4

我们在 bar 函数的外部,定义了一个立即执行函数,这样,在每次循环时,当前循环变量 i 的值都被传递到了函数内部的 j 变量,所以能得到我们想要的结果。

其实还有一种更简单的解决方法,直接将声明循环变量 i 的关键字 var 改为 let 也能同样达到效果,读者可以自行尝试。

立即执行函数探索,谨慎尝试

我在上面举了一个使用立即执行函数初始化数据的例子:

var num = (function (a, b) {
return a + b;
})(1, 2);

其实这种写法不使用括号把函数包起来也是可以的:

var num = function (a, b) {
return a + b;
}(1, 2);

同样能得到正确的结果,并且 JavaScript 解释器并没有报错。

实际上,在执行赋值操作的时候,上面的代码已经变成了一个表达式,而 JavaScript 解释器认为 函数表达式 是可以直接被执行的。

所以下面的代码也能够被正确执行:

+function () {
console.log(123);
}();
-function () {
console.log(123);
}();

注意这里的 +- 代表正、负,并不是加、减。JavaScript 有相当多的这种比较鬼畜的写法,并不建议大家在实际工作中使用,仅供娱乐。

首发地址: https://jianghushinian.cn/
版权声明
本文为[江湖十年]所创,转载请带上原文链接,感谢
https://segmentfault.com/a/1190000039051615

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云