JavaScript性能优化4——循环添加事件实现

Posted JIZQAQ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript性能优化4——循环添加事件实现相关的知识,希望对你有一定的参考价值。

目录

一、需求 

二、实现方式

1.闭包和自定义属性方式

代码

分析

2.事件委托方式

代码

分析


一、需求 

现在我们的页面上有3个按钮,我们需要用循环来给按钮添加事件,实现按按钮1的时候打印出当前索引值为0,按按钮2的时候打印出当前索引值为1,按按钮3的时候打印出当前索引值为2.

二、实现方式

1.闭包和自定义属性方式

代码

看下面代码,最开始的时候写了个普通的循环,但是发现并不能满足我们的需求。

于是后面我们倚靠闭包的机制写了另外3段代码和自定义属性写了1段代码,执行过后发现都能够完成我们需要的功能。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>循环添加事件</title>
        
    </head>
    <body>
        <button>按钮1</button>
        <button>按钮2</button>
        <button>按钮3</button>
        <script>
            var aButtons = document.querySelectorAll("button")
            console.log(aButtons)
            //无论点击哪个代码,输出的结果i都是3
            /*
            for(var i = 0;i < aButtons.length;i++){
                aButtons[i].onclick = function() {
                    console.log(`当前索引值为${i}`)
                }
            }
            */
            // 我们需要的是点击第一个按钮输出的i是0,第二个是1,第三个是2
            // 完成我们的需求的话,有下面几种办法
            /*
            * 闭包
            * 自定义属性
            * 事件委托
            */
            //闭包方法1:最普通的方法,把函数改成立刻执行的
            /*
            for(var i = 0;i < aButtons.length;i++){
                (function (i) {
                    aButtons[i].onclick = function() {
                        console.log(`当前索引值为${i}`)
                    }
                })(i)
            }
            */
            //闭包方法2:
            /*
            for(var i = 0;i < aButtons.length;i++){
                aButtons[i].onclick = (function(i) {
                    return function() {
                        console.log(`当前索引值为${i}`)
                    }
                })(i)         
            }
            */
            //闭包方法3:ES6中的let关键词
            /*
            for(let i = 0;i < aButtons.length;i++){
                aButtons[i].onclick = function() {
                    console.log(`当前索引值为${i}`)
                }
            }
            */
           //自定义属性
           for(var i = 0;i < aButtons.length;i++){
                aButtons[i].myIndex = i
                aButtons[i].onclick = function() {
                    console.log(`当前索引值为${this.myIndex}`)
                    //console.log(`当前索引值为${aButtons[i].myIndex}`) 这么写会报错TypeError: Cannot read property 'myIndex' of undefined
                }
            }
        </script>
    </body>
</html>

分析

闭包方法:

自定义属性方法:

上面两个办法对比,我们会发现,其实在自定义属性方法里面,我们并没有开辟新的空间,也就是没有形成所谓的闭包,在内存使用上是比较优秀的。它做的是往已经存在的对象上面添加了属性而已。

闭包其实是个非常优秀的机制,十分方便,便于我们去实现一些高阶的编程,但是在小的细节上比如内存管理这块,是不那么友好的。如果有其他替代方案的时候,也是可以用非闭包的方案实现。

2.事件委托方式

代码

我们在button的html上添加了index属性,每次点击的时候获取按钮的index属性的值并打印

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>循环添加事件</title>
        
    </head>
    <body>
        <button index='0'>按钮1</button>
        <button index='1'>按钮2</button>
        <button index='2'>按钮3</button>
        <script>
            //事件委托
            document.body.onclick = function(ev) {
                var target = ev.target
                targetDom = target.tagName
                if(targetDom === 'BUTTON') {
                    var index = target.getAttribute('index')
                    console.log(`当前索引值为${index}`)
                }
            }
        </script>
    </body>
</html>

分析

因为这里只有一个function,我们只需要开辟一个空间存一下我们的匿名函数,这个函数在被调用的时候进栈,有一个执行上下文执行。执行完了之后发现全局也并没有对它进行引用,当前的栈空间立马被释放。

所以这种做法无论是在内存上面,还是在数据存取访问的深度上面都是最优的。

以上是关于JavaScript性能优化4——循环添加事件实现的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript事件循环及任务处理

JavaScript事件循环及任务处理

JavaScript性能优化之事件委托

JavaScript性能优化9——减少判断层级减少循环体活动

JavaScript性能优化9——减少判断层级减少循环体活动

vue nextTick深入理解-vue性能优化DOM更新时机事件循环机制