立即执行函数/闭包深入/逗号运算符

0 阅读4分钟

📌 立即执行函数IIFE(immediately invoked function expression)

立即执行函数

创建后立即执行,本质是函数表达式

  • 页面加载自动执行,执行完成立即销毁(故忽略函数名)
//第一种写法----------------------
(function(){ 
   ...
})();
  
//第二种写法【W3C建议写法】---------------------
(function(){ 
    ...
}());

函数只要以表达式形式出现,无论有名与否,无论执行与否,其自动忽略函数名,通过函数名调用会报错,typeof检测类型为undefined

注意:错误写法——报语法错误

Uncaught SyntaxError: Unexpected token ")"

//错误的写法
function (){ 
    ... 
}();    //报错: Uncaught SyntaxError: Unexpected token (
  • 错误原因
    • 一定是表达式才能被执行符号执行
      • 语句后的()会被当做分组操作符,分组操作符里不能未空必须有表达式,所以报错
      • 即使()内有值或表达式,JavaScript引擎会将其当作单独的表达式来解析,不报错,函数因未被调用而不会执行
    • 因其执行完成立即销毁,所以立即执行函数忽略函数名(在其外部使用函数名调用报错未定义)
//让Javascript引擎认为这是一个表达式的方法还有很多
!function(){}();
+function(){}();
-function(){}();
~function(){}();
0 || function(){}();
1 && function(){}();
new function(){ /* code */ }
new function(){ /* code */ }() // 只有传递参数时,才需要最后那个圆括号

经典实用场景案例

利用立即执行函数弹出对应事件索引

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>利用立即执行函数弹出对应事件索引</title>
</head>

<body>
    <ul>
        <li>点击,打印0</li>
        <li>点击,打印1</li>
        <li>点击,打印2</li>
        <li>点击,打印3</li>
        <li>点击,打印4</li>
    </ul>
    <script>
        var lis = document.querySelectorAll("li")
        for (var i = 0; i < lis.length; i++) {
            (function (j) {
                lis[j].addEventListener('click', function () {
                    console.log(j);
                })
            }(i))
        }
    </script>
</body>

</html>

立即执行函数 和 闭包 的区别 ?

两者经常会结合在一起使用,但其两者本质不同

  • 共同点
    • 可以减少全局变量的使用
  • 不同点
    • 立即执行函数:声明之后立即执行,一般只调用一次后立即销毁,不占内存空间
    • 闭包:让外部可以访问其内部作用域,保证内部变量安全,但其内部变量被引用无法销毁,增加了内存消耗,可能造成内存泄漏

📌 逗号运算符

逗号运算符

执行所有的操作数,只返回最后一个操作数的值

逗号运算符在JavaScript中的优先级是最低的

  • 单一var声明模式,多个变量连续赋值
var a = 1,b = 2,c = 3,d = 4;

// 等价于--------------------------------
var a = 1;
var b = 2;
var c = 3;
var d = 4;
  • 逗号运算符可用于赋值,返回表达式中的最后一项
var num = (1,2,3,4,5);
console.log(num); // 5
  • 常用于for循环中,可循环多个变量
for(var i= 0,j = 10; i < j; i++, j--){
	console.log(i + j)     // 10 10 10 10 10
};  

📋 练习

1、累加器,初始值0,利用闭包,执行闭包函数,每执行一次+1

2、缓存器,利用闭包,学生名保存在数组里,两个方法写在函数的对象中,

  方法一功能加入班级,方法二功能离开班级,每次加入或离开都需答应班级人员新名单
// 累加器,初始值0,利用闭包,执行闭包函数,每执行一次+1

function accumulation() {
    var init = 0;
    return function () {
        init++
        console.log(init);
    }
}
var add = accumulation()

add(); //1
add(); //2
add(); //3
add(); //4
add(); //5

-------------------------------------------------------------
  
/*
 *缓存器,利用闭包,学生名保存在数组里,两个方法写在函数的对象中
 *功能方法一加入班级,
 *功能方法二离开班级,
 *每次加入或离开都需打印班级人员新名单
 */

function cache() {
    var students = [];
    function add(newName) {
        students.push(newName)
        console.log('欢迎' + '【' + newName + '】' + '同学加入!' + '目前班级人员名单如下:');
        for (var i = 0; i < students.length; i++) {
            console.log(students[i]);
        }
    }
    function leave(oldName) {
      	var idx = students.indexOf(oldName)
        if (idx == -1) return console.log('----查无此人----');
        students.splice(idx, 1)
        console.log('送别' + '【' + oldName + '】' + '同学!' + '目前班级人员名单如下:');
        if (students.length <= 0) return console.log('班级人数已经清0,目前已无人员信息');
        for (var j = 0; j < students.length; j++) {
            console.log(students[j]);
        }
    }
    return { add, leave }
}

var res = cache()

res.add('张三')   //欢迎【张三】同学加入!目前班级人员名单如下:张三
res.add('王五')   //欢迎【王五】同学加入!目前班级人员名单如下:张三 王五
res.add('李四')   //欢迎【李四】同学加入!目前班级人员名单如下:张三 王五 李四

res.leave('小李') //----查无此人----

res.leave('张三') //送别【张三】同学!目前班级人员名单如下:王五 李四
res.leave('李四') //送别【李四】同学!目前班级人员名单如下:王五 
res.leave('王五') //送别【王五】同学!目前班级人员名单如下:班级人数已经清0,目前已无人员信息

res.leave('张三') //----查无此人----