7 - 立即执行函数、闭包深入、逗号运算符

154 阅读3分钟

一、立即执行函数

  1. 一定是表达式才能被执行符号执行;

  2. 让函数声明变成表达式的方法:在函数声明前加:+ - || && !

  3. 函数声明后面不能跟立即执行符号(),例如function test(){}(),这样会报语法错误,function test(){}(1),这样不报错,但是也不执行,这样js引擎会认为这是一个函数声明+表达式,所以不报错;

  4. 立即执行函数在执行完就会销毁函数,不占用内存空间;

  5. 立即执行函数会自动忽略表达式里函数的名称;

1. 一定是表达式才能被执行符号执行

/*
* 立即执行函数的写法:
* 在立即执行函数前面写分号“;”的原因:js压缩之后变成一行,不同的立即执行函数直接要用“;”隔开防止
* 报错,在立即执行函数后面写也是可以的,只是在前面更容易记得写
* 
**/
//方法1:
;(function(){

})()

//方法2:也是w3c推荐的写法
;(function(){
  
}())

2. 让函数声明变成表达式的方法:在函数声明前加:+ - || && !

// 1. 函数声明前加 +
+function test1(){
   console.log("函数声明前加+");
}();

// 2. 函数声明前加 -
-function test2(){
   console.log("函数声明前加-");
}();

// 3. 函数声明前加  ||
false || function test3(){
   console.log("函数声明前加||");
}();

// 4. 函数声明前加  &&
true && function test4(){
   console.log("函数声明前加&&");
}();

// 2. 函数声明前加 !
!function test5(){
   console.log("函数声明前加!");
}();

3. 函数声明后面不能跟立即执行符号(),例如function test(){}(),这样会报语法错误,function test(){}(1),这样不报错,但是也不执行,这样js引擎会认为这是一个函数声明+表达式,所以不报错;

// 1. 函数声明后面加立即执行符号()--报错:Uncaught SyntaxError: Unexpected token ')'
function test(){
  console.log("我想立即执行。")
}();


/**
* 2.函数声明后面加立即执行符号(),立即执行符号有参数1,不报错,但是也不执行;
* 原因:js引擎会认为这是一个函数声明+表达式,所以不报错
*/
function test(){
  console.log("我想立即执行。")
}(1);

4. 立即执行函数传参,获取立即执行函数里面的返回值;

var sum = (function(a,b){
  var c = a + b;
  console.log(c); //3
  return c;  
})(1,2);

console.log(sum); //3

二、闭包深入

1. 闭包案例分析1:

function test() {
  var arr = [];
  //分析:循环里,只有当i=10时,循环才结束,所以无论传什么进来,它都只会打印最后一个值10
  for (var i = 0; i < 10; i++) {
    arr[i] = function () {
      console.log(i + ' ');
    }
  }
  return arr; 
}
var arr = test();
for (var j = 0; j < 10; j++) {
  arr[j](); //无论j是什么,上面的循环都是走到10才结束,只打印循环终止的最后一个值10
}

//打印结果: 10个10

2. 闭包案例分析2:

function test() {
  var arr = [];
  for (var i = 0; i < 10; i++) {
    // 立即执行函数,循环一次,执行一次
    (function (j) {
      arr[j] = function () {
        console.log(j + ' ');
      }
    })(i) //i的值为0-9
  }
  return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
  arr[j](); //
}

//打印结果: 0-9

3. 拓展:通过上面的案例,可以给列表绑定方法

<body>
    <ul>
        <li>0</li>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
</body>

//js代码
var oLi = document.querySelectorAll('li'); //获取li选择器
var oLength = oLi.length; //获取li的个数
for(var i = 0; i < oLength; i++){
  ;(function(j){
    //给每个li都绑定方法
    oLi[j].onclick = function(){
      console.log(j);
    }
  })(i)
}

三、逗号运算符:只返回最后一位

案例1:

var num = (1,2); 
console.log(num) // 2

案例2:

var fn = (
  function test1() {
    return 1;
  },

  function test2() {
    return '2';
  }
)();

console.log(typeof(fn)); 
// 打印结果: 'string'

/**
*  1. 立即函数里面有两个返回值1'2',但是逗号运算符只返回最后一位,所以fn = '2';
*  2. typeof('2') -> string
*/

四、案例合集

1. 面试题:

var a = 10;
if (function b(){}) {   //()表达式,忽略函数名
  a += typeof(b); // a = a + typeof(b) = 10 + typeof(undefined);
}

console.log(a); 
//打印结果:10undefined
/**
*  1. ()表达式,忽略函数名,所以b的值为undefined;
*  2. typeof(undefined)为undefined
*/

2. 闭包实现累加器

function sum(){
  var n = 0;
  function add(){
    n++;
    console.log(n);
  }
  return add;
}
var add = sum(); //将sum()里n的值保存到全局
add(); //1
add(); //2

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

function student(){
  var students = ['may','mike','lily'];
  var operations = {
    join:function(name){
      students.push(name);
      console.log(students);
    },
    leave:function(name){
      /**
      * 1. indexOf 方法返回一个整数值,返回第一次出现的指定子字符串在此字符串中的索引。
      * 2. 如果没有找到子字符串,则返回-1
      * 3. splice(index,1):如果index为负数,则是从右边起的第几位
      */
      
      // 方法1:使用indexOf实现
      var sIdx = students.indexOf(name); //sIdx不为-1即存在
      //判断要删除的学生是否在数组里
      if(sIdx != -1){
         students.splice(sIdx,1); //从sIdx位开始,删除1位
      }
      
      //方法2:使用for循环实现
      for(var i = 0; i < students.length; i++){
        var item = students[i]; // 把每一项缓存到item中,优化for循环的性能
        if(item === name){
          students.splice(i,1); //从i位开始,删除1位
        }
      }
      console.log(students);
    }
  }
  return operations;
}

var student = student();
student.join('jon'); //["may", "mike", "lily", "jon"]
student.leave('may'); //["mike", "lily", "jon"]