ERROR:控制台会报出: is not defined 错误

问题描述 : 如果我们对于一组元素(相同的标签)同时进行onclick事件处理的时候(在需要获取到索引的时候),一般是写一个for循环,但是onclick是一个异步调用的,所以会带来一个问题,当我们触发这个事件的时候,我们能获取的i值是for完整执行完后i的值,而不能获取到代码顺序里i的值


以前惯用的解决方式

    <script type="text/javascript">
        window.onload = funtion(){
            var lis = document.getElementsByTagName('li');
            for( var i = 0; i < lis.length; i ++ ){
                lis.index = i;
                lis[i].onclick = function(){
                    console.log( this.index );
                };
            }
        };
    </script>

利用闭包解决(一)

增加若干个对应的闭包域空间(采用匿名函数实现)专门用来存储原先需要引用的内容(下标值),只限于基本类型(基本类型值传递,对象类型引用传递)

    <script type="text/javascript">
        for(var m =0 ; m< spanBtn.length ; m++){
            !function(i){
                spanBtn[i].onclick = function(){
                    for(var j =0 ; j<imgbox.length; j++)
                    imgbox[j].style.display = "none";
                    imgbox[i].style.display = "block";
                }
            }(m)
        }
    </script>

利用对象属性(二)

将下标作为对象属性(name:"i",value:i的值)添加到每个数组项(p对象)中

    <script type="text/javascript">
        for(var i=0; i<arr.length; i++){
            //为当前数组项(当前p对象)添加一个名为i的属性,值为循环体i变量的值
            //此时当前p对象的i属性并不是对循环体的i变量的引用,而是一个独立p对象的属性,属性值在声明的时候就确定了
            arr[i].i = i;
            arr[i].onclick = function (){
                console.log(this.i);
            }
        }
    </script>

匿名闭包空间(三)

增加若干个对应的闭包域空间用来存储下标 新增的匿名闭包空间内完成事件绑定(三)

    //绑定的函数中的function scope中的closure对象的引用arg是指向将其返回的匿名函数的私有变量arg
    <script type="text/javascript">
        for(var i = 0; i<arr.length; i++){
            arr[i].onclick = (function(arg){
                return function () {
                    console.log(arg);
                }
            })(i);
        }
    </script>

使用ES6的let关键字(四)

    "use strict";
    var arr = document.getElementsByTagName("p");
    for(var i = 0; i<arr.length; i++){
        let j = i;//块级变量
        arr[i].onclick = function () {
            console.log(j);
        }
    }

知识点总结

1 . 要解决此问题,首先要了解闭包的概念。闭包是JavaScript语言的一个难点,也是它的特色,很多高级应用都要依靠它来实现。

[ 闭包概念 ]:简而言之,闭包就是能够读取其他函数内部变量的函数,由于在JavaScript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成定义在一个函数内部的函数。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

2 . 闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

3 . 使用闭包的注意点

[ 1 ] 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

[ 2 ] 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。