立刻执行函数、插件和面试题

定义

  • 立刻执行函数:功能化称呼-初始化函数
  • IIFE:immediately invoked function expression(立即执行函数表达式)
  • 特点:页面加载自动执行、执行完成以后立刻释放

三种基本写法

// 第一种
(function(){

})(); // 看着清晰

// 第二种
(function(){

}()); // W3C建议

// 第三种
+function test(){

}()

示例、参数、返回值

// 1、简单示例
// 用括号包裹匿名函数:因为括号包裹的是函数表达式,前后需要加分号
(function(){
    var a = 1;
    var b = 2;
    console.log(a + b); // 3
}());


// 2、参数问题
(function(a, b){ // 形参
    console.log(a + b); // 3
}(1, 2)); // 实参


// 3、返回值:用变量接受表达式
var num = (function(a, b){
    return a + b;
}(1, 2));

console.log(num); // 3

表达式执行

(1)括号包起来的一定是表达式

(funiton test(){})

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

// 被执行
(function test1() {
    console.log(1); // 1
})();

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

// 不传参报错,不是一个表达式,原因:JS引擎认为不传参数就是不是表达式
// 报语法错误:Uncaught SyntaxError: Unexpected token )
function test3() {
    console.log(1);
}(); // 没传参

// 传入参数不报错,但不执行,原因:JS引擎认为传了参数就是表达式
function test5(a) {

}(6);  // 传入参数

(3)立刻执行函数:自动执行、执行完成以后立刻释放

// 括号包裹-会报错
(function test(){
    var a = 1;
    var b = 2;
    console.log(a + b); // 3
}());
// 因为执行完毕即可销毁,外部调用不到test函数
console.log(test()); // Uncaught ReferenceError: test is not defined

// 表达式-不会报错
var test1 = function() {
    console.log(2); // 2
}();
console.log(test1); // undefined

(4)如果函数变为表达式,函数名就会被忽略

// 匿名函数
var num = (function(){
    return 123;
})();
console.log(num); // 123

// 忽略函数名
var num = (function test(){
    return 123;
})();
console.log(num); // 123

(5)函数声明变为表达式的方法,在表达式前加 +、-、!、||、&&

// 1、函数声明:function test(){}
// 2、函数声明变为表达式(前面加符号):+function test(){}
// 3、表达式立刻执行(末尾加括号):+function test(){}()
+function test() {
    console.log(1);
}();

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

立刻执行函数-插件

(1)window与return的闭包返回

// window与return:作用一样
function testCal() {
    var a = 1;
    function plus() {
        a++;
        console.log(a);
    }

    // window.plus = plus;
    return plus;
}

var plus = testCal();

plus(); // 2
plus(); // 3
plus(); // 4

(2)插件写法

//外层匿名函数包裹:隔离作用域,防止全局函数和变量污染
// 防止出错,默认加分号,变成表达式
(function(){
    function Test() {

    }

    window.Test = Test;
})();
// 调用
var test = new Test();


// 更好的写法:默认前面加分号
;(function(){
    function Test() {

    }

    window.Test = Test;
})()
// 调用
var test = new Test();

立刻执行函数-经典面试题一

function test() {
    var arr = [];

    for(var i = 0; i < 10; i++) {
        // 赋值语句,系统定义的时候为函数引用,访问不到里面的值
        // 只有在外部执行的时候才会看到里面的i值
        arr[i] = function() { // 匿名函数
            document.write(i + ' ');
        }
    }

    // for循环 等价
    // var i = 0;
    // for(; i < 10; ) {
    //     arr[i] = function() {
    //         document.write(i + ' ');
    //     }
    //     i++;
    // }

    return arr;
}

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

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

// 答案: 10个10
// 原因:
// 1、test中的for循环,在arr中存放了10个匿名函数,但是没执行
// 2、当for循环完毕之后,test函数中AO存放的i变量已经变为了10
// 3、当return arr的时候,形成了10个闭包,即10个匿名函数,虽然test的AO被销毁,但是返回的每个匿名函数中都有test的AO
// 4、当在外部for循环调用每个匿名函数的时候,输出的i都是10

如果想打印0-9,的解决方法:

// 第一种方法:需要立刻执行函数
function test() {
    //var arr = [];

    for(var i = 0; i < 10; i++) {
        // 改为立刻执行函数
        (function() {
            document.write(i + ' ');
        }());
    }

    //return arr;
}
test();


// 第二种方法:外部传入
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); // 0 1 2 3 4 5 6 7 8 9
}


// 第三种方法:立刻执行保存值(最常用)
function test() {
    var arr = [];

    for(var i = 0; i < 10; i++) {
        // 实际循环立刻执行函数:立刻执行函数保存i值
        (function(j){
            // 立即执行函数AO中的 j = 0, 1, 2, 3......
            // 每个立刻执行函数中都有一个唯一的j值
            arr[j] = function() {
                // 访问的是立刻执行函数AO中的j值:0, 1, 2.... 
                document.write(j + ' ');
            }
        })(i);
    }

    return arr;
}

var myArr = test();
console.log(myArr); // [ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ]

for(var j = 0; j < 10; j++) {
    myArr[j](); //0 1 2 3 4 5 6 7 8 9
}

立刻执行函数-经典面试题二

点击li的数字打印出对应的数字值

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo列表</title>
<body>
    <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++) {
            // 每次点击都是5
            // oLi[i].onclick = function() {
            //     console.log(i);
            // }

            // 立刻执行函数包裹解决
            (function(j){
                oLi[j].onclick = function() {
                    console.log(j + 1);
                }
            })(i);
        }
    </script>
</body>
</html>

立刻执行函数-括号运算面试题

// 逗号运算:返回最后一个
var num = (2 - 1, 6 + 5, 24 + 1);
console.log(num); // 25

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

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

// 1、括号中有逗号,返回执行的是test2函数,
// 2、然后立即执行,又return '2',最后返回为字符串2
console.log(fn); // '2'
console.log(typeof fn); // 'string'
var a = 10;
if (function b(){}) { // 函数声明为true
    // 因为b函数声明被括号括起来了,所以(function b(){})为表达式,忽略了函数名b,所以没有b
    a += typeof(b); // 因为b没有,所以typeof b为'undefined'
}
console.log(a); // '10undefined'