循环添加事件底层执行分析、原理分析,闭包及其可能的负面影响、自定义属性思想解决

底层分析

3个按钮-NodeList


HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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 src="./add-event-loop.js"></script>
</body>
</html>

原始代码图解分析,为何打印结果都为3?

原始代码

// add-event-loop.js
var aButtons = document.querySelectorAll('button');
for (var i = 0; i < aButtons.length; i++) {
    aButtons[i].onclick = function() {
        // 下面的this 就是触发onclick事件的dom对象,即aButtons[i]
        console.log(`当前索引值为${i}`); 
    }
}
图示分析
  • 图示1-初始化内存图示
    在这里插入图片描述
  • 图示2-第一轮循环
    在这里插入图片描述
  • 图示3 - 三轮循环产生的内存使用
    在这里插入图片描述
  • 图示4 - onclick中存地址
    在这里插入图片描述
  • 图示5 - 点击事件进栈执行
    在这里插入图片描述
  • 图示6 - 整体执行流程结束
    在这里插入图片描述

基于闭包思想改良,能够正确打印结果,从内存使用角度分析其性能

闭包改良版

// add-event-loop.js
var aButtons = document.querySelectorAll('button');
// 方式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)
}
图示分析
  • 图示1 - 初始化
    在这里插入图片描述
  • 图示2 - onclick进行赋值
    在这里插入图片描述
  • 图示3
    在这里插入图片描述
  • 图示4 - 完整流程明细
    在这里插入图片描述
闭包可能带来的负面影响

开辟一个(堆)内存空间存储函数表示一个函数的创建,进栈执行表示函数的执行,一般函数执行完成之后会进行出栈并释放堆内存空间,而使用闭包的话则不会出栈释放内存空间,会一直往执行环境栈中添加执行上下文,一直行进堆内存的占用,增加内存负担
在这里插入图片描述

  • 在使用闭包时注意内存溢出,在合适位置清除内存引用
    在这里插入图片描述

自定义属性改良版,相较于闭包版优势在哪?

不会开辟新的内存空间,对内存的消耗较小,与原始版代码底层原理相同,只是在每个button(事件)对象身上加了新的属性
自定义属性代码

// add-event-loop.js
var aButtons = document.querySelectorAll('button');
for (var i = 0; i < aButtons.length; i++) {
    aButtons[i].myIndex = i;
    aButtons[i].onclick = function() {
        // 下面的this 就是触发onclick事件的dom对象,即aButtons[i]
        console.log(`当前索引值为${this.myIndex}`); 
    }
}
图示分析
  • 图示1 - 初始化
    在这里插入图片描述
  • 图示2 - 开始执行循环
    • 相当于在每个button对象里加了一个myIndex的属性
      在这里插入图片描述
  • 图示3 - 事件执行
    在这里插入图片描述

ES6 let关键字版

ES6版代码

// add-event-loop.js
// 3.ES6 let关键字:同样也是基于闭包思想
var aButtons = document.querySelectorAll('button');
for (let i = 0; i < aButtons.length; i++) {
    aButtons[i].onclick = function() {
        console.log(`当前索引值为${i}`); 
    }
}

其底层原理与闭包相同,其实也是基于闭包基础的


事件委托机制解决循环添加事件的问题、底层执行分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值