JavaScript基础练习_day4
### JavaScript基础练习_day4 #### 知识点概述 本次基础练习主要针对JavaScript中的几个核心概念进行探讨,包括但不限于变量作用域、异步操作、定时器的行为以及闭包的应用等。通过具体的代码示例,帮助初学者理解这些概念在实际编程中的应用方式。 #### 代码分析 **原始代码** ```javascript for(var i=0; i<5; i++){ setTimeout(function(){console.log(i);},1000); } console.log(i); ``` 这段代码的关键在于理解和掌握`setTimeout`的异步行为以及`for`循环中的变量作用域。 1. **运行结果**: - 当`for`循环执行完毕后,`i`的最终值为`5`。 - `setTimeout`中的回调函数将在1秒后被执行,但由于循环结束后`i`的值已经变成了`5`,因此无论何时执行回调函数,`console.log(i)`都会输出`5`。 - 因此,最终输出的结果为`5=>5,5,5,5,5`,其中`5`首先被打印出来,紧接着是`setTimeout`回调函数中的五个`5`,它们几乎同时被打印出来。 2. **期望输出**:`5=>0,1,2,3,4` 为了达到这个输出效果,我们需要解决`setTimeout`中的回调函数访问到的是`for`循环结束后的`i`值的问题。下面提供了两种改造方案: - **解法1:利用立即执行函数IIFE** ```javascript for(var i=0; i<5; i++){ (function(j){ setTimeout(function(){ console.log(j);},1000); })(i); } console.log(i); ``` 在这里,我们通过创建一个立即执行的匿名函数并传入当前循环的索引`i`作为参数`j`,从而确保每个回调函数都有自己的`j`副本,这样就不会受到循环结束后`i`的变化影响了。 - **解法2:利用按值传递,循环中调用普通函数,而不是回调函数** ```javascript var output=function(i){ setTimeout(function(){ console.log(i);},1000); }; for(var i=0; i<5; i++){ output(i); } console.log(i); ``` 这里我们将`setTimeout`的逻辑封装到了一个独立的函数`output`中,每次循环调用`output`函数并传入当前的`i`值。这样做的效果与解法1类似,也是保证每个`setTimeout`回调中的`i`都是独立的。 3. **思考:利用ES6的`let`,可以吗?** 使用`let`代替`var`来声明循环变量可以在一定程度上避免这个问题,因为`let`具有块级作用域,这意味着每次循环都会创建一个新的绑定。因此,每个`setTimeout`回调函数都将会拥有它自己局部的`i`值,不会受循环结束后`i`的变化影响。修改后的代码如下: ```javascript for(let i=0; i<5; i++){ setTimeout(function(){console.log(i);},1000); } console.log(i); ``` 这样就可以实现预期的输出`5=>0,1,2,3,4`。 4. **期望输出**:`0=>1=>2=>3=>4=>5` 如果希望输出`0`至`4`按照顺序依次延迟1秒打印,最后再打印出`5`,可以考虑以下几种方案: - **解法1:利用按值传递,每次递增计时器的延时** ```javascript var output=function(i){ setTimeout(function(){ console.log(i);},1000*i); }; for(var i=0; i<5; i++){ output(i); } setTimeout(function(){ console.log(i);},1000*i); ``` 这种方法中,我们通过将延时时间设置为`1000 * i`,确保了每次输出的`i`值按顺序打印。 - **解法2:利用立即执行函数IIFE,思路同解法1** ```javascript for(var i=0; i<5; i++){ (function(j){ setTimeout(function(){ console.log(j);},1000*j); })(i); } setTimeout(function(){ console.log(i);},1000*i); ``` 这种方法同样利用了IIFE来保证每次`setTimeout`中的`i`值独立,并通过调整延时时间来控制输出顺序。 - **解法3:利用ES6的`Promise`** ```javascript const tasks=[]; const output=(i)=> new Promise((resolve)=>{ setTimeout(()=>{ console.log(i); resolve();},1000*i); }); for(var i=0; i<5; i++){ tasks.push(output(i)); } Promise.all(tasks).then(()=>{ setTimeout(()=>{ console.log(i);},1000); }); ``` 这里我们使用了`Promise.all`来等待所有任务完成后再执行最后一个`setTimeout`,从而实现了按顺序输出。 #### SetTimeout定时是否准确? `setTimeout`的定时并不总是精确的。这是因为浏览器或Node.js的事件循环机制可能会导致定时任务的实际执行时间比预期稍晚。例如,如果有大量的同步代码在执行,或者线程阻塞等情况发生,那么`setTimeout`的实际触发时间可能会有所延迟。具体原因可参考[关于setTimeout的深入解析](http://caibaojian.com/about-settimeout.html)。 #### 闭包的理解 闭包是指有权访问另一函数作用域中的变量的函数。创建闭包最常见的方式就是在一个函数内部创建另一个函数。闭包的特性使得它可以记住在其外部创建的变量,即使创建它的函数已经返回了。这种特性在JavaScript中非常有用,因为它可以用于创建私有变量和方法,以及维护状态等。更多关于闭包的信息可以参考[学习JavaScript闭包](http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html)。 总结来说,本练习涉及了JavaScript中多个重要的基础概念,包括作用域、异步处理、定时器的行为以及闭包的应用等。通过实际操作和思考,可以帮助初学者更好地理解这些概念,并在实际开发中正确地运用它们。






















- 粉丝: 96
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


最新资源
- 单片机教室照明控制系统的设计与实现.docx
- 对抗训练与多模态特征融合的情感识别算法优化研究.docx
- 电气自动化与人工智能融合的现状、趋势与展望.docx
- 电动振动台非线性控制算法优化及前馈控制技术研究.docx
- 分析人工智能技术可能带来的社会风险及其治理机制.docx
- 服务器维保服务规划与实施策略研究.docx
- 多目标优化算法在农业种植结构中的应用.docx
- 改进ESMDO算法在PMSM双惯量系统无模型滑模控制中的应用研究.docx
- 改进YOLOv5n算法与仿生海豚模型在目标识别跟踪中的应用.docx
- 复合窗幕系统建筑能耗模拟:DesignBuilder软件参数化建模与验证.docx
- 高校美育的人工智能赋能:机遇与挑战分析.docx
- 国产大模型舆情演化模拟:基于LLM增强的主题建模.docx
- 海上风电基础冲刷深度预测模型构建及机器学习算法应用.docx
- 高保密软件开发项目信息资产的分类分级管理与全生命周期控制研究.docx
- 互联网技术支持下高校课堂参与度提升路径研究.docx
- 互联网直播虚假宣传的法律监管与治理策略研究.docx


