0. 引入:

问题:全局声明的函数,始终都在GO里,不释放,随时随地都能调用
需求:函数立即执行,执行完成后立即释放

解决:
立即执行函数 IIFE - immediately invoked function expression
功能上又称 初始化函数

1. 写法:

  1. // 写法1 - 使用更多
  2. (function() {})();
  3. // 写法2 - W3C建议
  4. (function() {}());

1.1 示例: 立即执行函数 返回值 赋给变量

  1. var num = (function(a, b){
  2. return a + b;
  3. })(1, 2);
  4. console.log(num);

2. 深入理解:

2.1 (函数声明)() -> 能执行(立即执行函数)

  1. (function(){
  2. console.log(1) ;
  3. })();

2.2 var a = 函数声明() -> 能执行

  1. var test = function(){
  2. console.log(1) ;
  3. }();

2.3 函数声明() -> 语法错误

  1. function(){
  2. console.log(1) ;
  3. }();

原因:

  • 只有表达式才能被执行符号()执行,函数声明不能被执行

    2.4 函数声明(参数) -> 无语法错误,函数未执行

    1. function test(a, b){
    2. console.log(a + b +1)
    3. }(6, 10) // 10

    原因:

  • 为避免报错,JS引擎不把(6,10)理解为执行符号,而理解为逗号运算表达式

  • ()内没有内容时,只能理解为执行符号,故而会报错
  • 逗号运算,返回逗号最后一个值

    1. function test(a, b){
    2. console.log(a + b +1)
    3. } // 函数声明
    4. (6, 10) // 逗号运算 -> 10

    2.5 + - ! && || 函数声明() -> 能执行

    1. 1 && function(){
    2. console.log(1) ;
    3. }();

    说明: 将函数声明变成表达式的方法

  • () 包裹

      • ! || &&

        2.6 函数声明变成表达式后,函数名被忽略

        ```javascript 1 && function test(){ console.log(1) ; }();

console.log(test); // Uncaught ReferenceError: test is not defined

  1. <a name="PTJvz"></a>
  2. ### 3. 面试题
  3. <a name="JqxFn"></a>
  4. #### 3.1 下面代码的执行结果,原因,改写
  5. ```javascript
  6. function test() {
  7. var arr = [];
  8. for(var i = 0; i < 10; i++){
  9. arr[i] = function() {
  10. document.write(i + ' ')
  11. }
  12. }
  13. return arr;
  14. }
  15. var myArr = test();
  16. for(var j = 0; j < 10; j++) {
  17. myArr[j]();
  18. }

执行结果:10 10 10 ... 10个10

原理:闭包
myArr[j] 函数的作用域链中保存了函数test 的 AO,因此打印 i = 10

改写,使其打印 0, 1, 2, 3, 4, 5, …

  1. function test() {
  2. var arr = [];
  3. for(var i = 0; i < 10; i++) {
  4. (function(j) {
  5. arr[j] = function() {
  6. document.write(j + ' ')
  7. }
  8. })(i)
  9. }
  10. return arr;
  11. }
  12. var myArr = test();
  13. for(var j = 0; j < 10; j++) {
  14. myArr[j]();
  15. }

3.2 点击某个li,打印其下标

  1. <body>
  2. <ul>
  3. <li>1</li>
  4. <li>2</li>
  5. <li>3</li>
  6. <li>4</li>
  7. <li>5</li>
  8. </ul>
  9. </body>
  1. var oLis = document.querySelectorAll("li");
  2. for(var i = 0; i < oLis.length; i++) {
  3. (function(j) {
  4. oLis[j].onclick = function () {
  5. console.log(j);
  6. }
  7. })(i)
  8. }

3.3 下面一段代码执行的结果

  1. var fn = (
  2. function test1() { return 1 },
  3. function test2() { return '2' }
  4. )();
  5. console.log(typeof fn) // -> 'string'

3.4 下面一段代码执行的结果

  1. var a = 10;
  2. if(function b() {}) {
  3. // !!function () {} === true -> 执行if中的语句
  4. // 函数声明变成表达式后,函数名被忽略,所以b不存在
  5. a += typeof(b);
  6. }
  7. console.log(a); // -> 10undefined

4. 作业

4.1 累加器

闭包实现,初始值为0,每执行一次+1

  1. function fCounter() {
  2. var num = 0;
  3. return function() {
  4. num ++;
  5. console.log(num);
  6. }
  7. }
  8. var counter = fCounter();
  9. counter();

4.2 学生名单管理

一个班级,学生名字保存在一个数组里,两个方法写在函数中的一个对象中,第一个方法加入班级,第二个方法离开班级,每次加入或离开都需要打印新的学生名单

  1. function fClassMana() {
  2. var stuList = [];
  3. var printStuList = function() {
  4. var s = ""
  5. for(var i = 0; i < stuList.length; i++) {
  6. stuList[i] && (s += stuList[i] + ' ')
  7. }
  8. console.log(s)
  9. }
  10. var classMana = {
  11. addStu: function(name) {
  12. stuList.push(name);
  13. printStuList();
  14. },
  15. removeStu: function(name) {
  16. for(var i = 0; i < stuList.length; i++) {
  17. if(stuList[i] === name) {
  18. stuList[i] = undefined;
  19. }
  20. }
  21. printStuList();
  22. }
  23. }
  24. return classMana;
  25. }
  26. var classMana = fClassMana();
  27. classMana.addStu("little N");
  28. classMana.addStu("little T");
  29. classMana.addStu("little S");
  30. classMana.removeStu("little T");