前端进阶|第九天 逆天的立即执行函数(IIFE)

NULLISNULL 2019-09-15

函数 class list ES6 IIFE

不多说,先看两道笔试题,首先上代码。
例1

    <script>
        window.onload = function () {
            var list = document.getElementsByClassName('list')
            for (var i = 0; i < list.length; i++) {
                list[i].addEventListener('click', function () {
                    alert(i);
                })

            }
        }      
    </script>
    <ul>
        <li class="list">点我1</li>
        <li class="list">点我2</li>
        <li class="list">点我3</li>
    </ul>

按照逻辑应该实现的效果是,我们点击每个元素,弹框提示对应元素的索引值,但真实的结果是无论我们点击哪个li,均弹出3.
例2来自京东的笔试题,代码如下

       var name = 'Tom';
        (function () {
            if (typeof name == 'undefined') {
                name = 'Jack';
                console.log('Goodbye ' + name);
            } else {
                console.log('Hello ' + name);
            }
        })();

如果我们不了解IIFE的执行逻辑,可能会认为输出是Hello Tom,然而程序的实际输出是Goodbye Jack。
要解决这两道题目,我们就要去搞明白IIFE的相关内容。
1 何为IIFE
IIFE( 立即调用函数表达式)顾名思义是一个在定义时就会立即执行的  [JavaScript]。
语法格式如下

 (function(){
            alert('hello world')
        })();

这两行代码完成了两个功能,声明了一个函数,并自己进行了调用。简单来说,我们以往定义的函数,如果要执行是需要调用的,可能是事件触发,也可能是我们直接调用。但IIFE明显独树一帜,完成声明后,自己调用执行自己,非常独立和自我。
2.IIFE的作用
解决了“我是谁 ”的问题,接着来看IIFE存在的意义是什么。
1)因为IIFE的执行是自主完成的,所以我们无需为其命名,这样可以避免全局性的变量污染。
2)IIFE圈地自治,IIFE函数体内的变量只在本作用域内有效,可以有效减少变量污染,同时实现变量私有,函数执行完成后,变量立即销毁。
3.如何使用IIFE
回到第一题,之所以会输出3,是因为点击函数并不是立即执行的,变量i的值在for循环里是在不断变化的,当for循环执行后,i的最终值为3,那么点击元素出发弹框后,会自动访问i的地址,找到的就是3。
使用立即执行函数可以有效解决这个问题。

        window.onload = function () {
            var list = document.getElementsByClassName('list')
            for (var i = 0; i < list.length; i++) {
                (function (i) {
                    list[i].addEventListener('click', function () {
                        alert(i);
                    })
                })(i)
            }
        }      

首先将每次绑定都改为立即执行函数,其次将i作为变量传入IIFE,这样for循环对i的更新将不会影响IIFE内的i。
除了这样修改,还可以用ES6的关键字let的替代var进行i声明,也可以解决这个问题。
第二个问题也迎刃而解,我们知道name的值并没有作为变量传入IIFE,那么if的时候name理所当然是未定义,此时程序走的第一个分支,输出的是Goodbye Jack。
光理解这个输出是不够的,可以试下,将立即执行函数的对name的声明改为let,你会发现,程序居然输出了Hello Tom。
0915

这个地方就有点吊诡了,看了资料分析说,是因为我用let声明的变量,引擎认为在IIFE内是有这个变量的,所以执行的时候会走else,但因为if分支并未执行,所以初始化称jack的操作没有进行,此时系统在本作用域内找不到name,就会逐级向上找,一直找到window,然后就找到了Tom。
好吧,js引擎是个任性boy,不按常理出牌,他的套路分分钟绕晕我。

登录 后评论
下一篇
corcosa
13348人浏览
2019-10-08
相关推荐
揭秘 IIFE 语法
682人浏览
2017-10-19 16:39:00
JavaScript 为什么快--第二篇
5399人浏览
2018-08-10 14:24:08
0
0
0
149