【ECMAScript 】立即执行函数、闭包深入、逗号运算符、表达式

1. 立即执行函数 IIFE -immediately-invoked function expression

全局的函数都保存在GO中,不释放,想调用的时候可以随时调用

function test1() {
  console.log(1);
}
function test2() {
  console.log(2);
}
test2();
function test3() {
  test1();
}
test3();
// 2 1

1.1 特点

  1. 自动执行
  2. 执行完成之后立即释放

立即执行函数 的功能性称呼:初始化函数

1.2 写法

  1. 写法一

    函数括起来之后再加(),也就是函数的执行

    一定是表达式才能被执行符号()执行

    (function(){
    
    })();
    // 函数括起来之后再加(),也就是函数的执行
    
  2. 写法二

    括号里面写函数声明,这个函数经过括号的包裹也就变成了表达式

    括号包任何东西都叫表达式,它也能转换成表达式

    把函数声明变成表达式之后,函数名就被自动忽略了

    // 写法2
    (function(){
    
    }()); // W3C 建议
    // 括号里面写函数声明,这个函数经过括号的包裹也就变成了表达式
    // 括号包任何东西都叫表达式,它也能转换成表达式
    

问题:下方代码是否能执行

function test(){
}();
// 报错:语法错误

var test = function(){
  console.log(1);
}(); // 可以执行

(function test(){
  console.log(1);
})(); // 可以执行,标准的立即执行函数

var test2 = function(){
  console.log(1);
}(); // 可以执行

function test3(){
  console.log(1);
}(); // 不可以执行,报错

// 一定是表达式才能被执行符号执行
// 括号包任何东西都叫表达式,它也能转换成表达式

需求:以下函数立即执行,并拿到值,执行完立即释放

add(1, 2);
function add(a, b) {
  console.log(a + b);
}

(function test(){
  var a = 1,
      b = 2;
  console.log(a + b);
}());

test; // 这个时候报错:test is not defined,从侧面印证了执行完立即释放;()->函数的执行符号

// 传参、返回值
var num = (function(a, b){
  return a + b;
}(2, 4));
console.log(num);
var test = function(){
  console.log(1);
}
console.log(test); // function(){...} 匿名函数

var test1 = function(){
  console.log(2);
}();
console.log(test1); // 2 undefined
// 证明了立即执行,执行完就销毁

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

// 1. 函数声明前加上符号 + - ! || &&
+ function test(){
  console.log(1);
}()

总结:将函数声明转换为表达式后就可以使用执行符号,立即执行该函数,并且该函数的函数名就自动被忽略掉了

1.4 面试题

1.4.1 下面代码会报错吗

function test(a){
  console.log(1);
}(6)

不会报错,括号里面传了值,就将其理解为一个表达式 (6),不将其认为是一个立即执行符号,如果是什么都不传,就会将其认为是立即执行符号,就会报错

1.4.2 for循环中返回结果是什么?为什么?

function test(){
  var arr = [];
  
  for(var i = 0; i < 10; i++){
    arr[i] = function(){
      document.write(i + ' ');
    }
  }
  return arr; // 这里形成了闭包
}

var myArr = test();
console.log(myArr); // [f,f,..] 是个匿名函数

for(var j = 0; j < 10; j++){
  myArr[j](); // 返回结果是什么?为什么
}

答: 十个10

因为每次给arr[i]赋值的时候,只是赋值了一个匿名函数,并没有执行,return 的时候,test的AO中 i已经变为10了,而且被arr中的每一个函数拽住,等到执行的时候,就都是 10 了

i 的值相当于下面的 test 中的 n

function test(){
  var n = 10;
   
  var a = function(){
    console.log(n);
  }
  
  var b = function(){
    console.log(n);
  }
  
  return [a, b];
}

var arr = test();
arr[0]();
arr[1]();

变形:上题中怎么能正确打印1-9

// 方法1:循环时立即执行
function test(){
  for(var i = 0; i < 10; i++){
     (function(){
      document.write(i + ' ');
    })() // 这里变为立即执行函数
  }
}
test();

// 方法2:传参
function test(){
  var arr = [];
  
  for(var i = 0; i < 10; i++){
    arr[i] = function(num){ // 传参
      document.write(num + ' ');
    }
  }
  return arr;
}

var myArr = test();
console.log(myArr); //

for(var j = 0; j < 10; j++){
  myArr[j](j);
}

// 方法3:保存每次立即执行的值(最常用)
function test(){
  var arr = [];
  
  for(var i = 0; i < 10; i++){
    (function(j){ // 每一次循环的时候,把 i 保存进立即函数里 ⭐
      arr[j] = function(){ // 每次替换的时候,arr[j]和j都会被替换,值不一样,循环的是立即执行函数
        document.write(j + ' ');
      }
    })(i)
    
  }
  return arr;
}

var myArr = test();
console.log(myArr); //

for(var j = 0; j < 10; j++){
  myArr[j]();
}

1.4.3 代码中点击 li返回的是什么

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<script type="text/javascript">
  var oLi = document.querySelectorAll('li');
  for(var i = 0; i < oLi.length; i++){
    oLi[i].onclick = function(){
      console.log(i);
    }
  }
</script>

// 答:每次点击返回的都是5
// 解决方法:立即执行函数
<script type="text/javascript">
  var oLi = document.querySelectorAll('li');
  for(var i = 0; i < oLi.length; i++){
    (function(j){
      oLi[j].onclick = function(){
        console.log(j);
      }
    })(i)
  }
</script>

1.4.4 代码中打印什么⭐

var a = 10;

if(function b(){}){ // 函数声明被()括起来了,变成表达式,名称被忽略了 ⭐
  a += typeof(b); // 所以没有 b
}
console.log(a); // 10undefined

2. 逗号运算符

返回最后一个逗号后面的值 ⭐

var num = (2 - 1, 6 + 5, 24 + 1);
console.log(num); // 25

面试题

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

3. 作业

  1. 累加器,初始值是0,写个闭包,执行一次函数,增加1打印一次

    function acc(){
      var num = 0;
      function add(){
        console.log(++num);
      }
      return add;
    }
    
    var fn = acc();
    fn();
    
  2. 缓存器,闭包,一个班级,学生的名字保存在一个数组里,两个方法写在函数中的一个对象中,第一个方法加入班级,第二个方法离开班级,每次加入或离开,传入学生的名字都需要打印新的学生名单

    function myClass(){
      var students = [];
      return {
        join: function(name){
          students.push(name);
          console.log(students);
        },
        leave: function(name){
          // 方法 1
          var idx = students.indexOf(name);
          if(idx !== -1) {
            students.splice(idx, 1);
          }
          // 方法 2
          // for(var i = 0; i < students.length; i++) {
          //  var item = students[i]; // 优化for循环性能的一种方法
          //  if(item === name){
          //    students.splice(i, 1);
          //  }
          // }
          console.log(students);
        }
      }
    }
    var c = myClass();
    c.join('Andy');
    c.join('Tom');
    c.join('Cindy');
    c.leave('Tom');
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值