示例代码托管在:http://www.github.com/dashnowords/blogs

博客园地址:《大史住在大前端》原创博文目录

华为云社区地址:【你要的前端打怪升级指南】

一. 题目

改造下面的代码,使之输出0 - 9,写出你能想到的所有解法。

首先作为前端开发者,你起码得知道下面的代码会输出什么,强烈建议自己动手试试能写出多少种解法。

for (var i = 0; i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)
}

二. 解法风暴

console.log(i)在执行时,会按照词法作用域来取得循环条件中的变量 i的值,本题的基本思路实际上就是如何在console.log语句for循环条件之间添加(或修改)代码来隔离变量 i的词法作用域。

解法一:最容易想到的方法——ES6块级作用域

//最容易想到的就是使用let实现的局部作用域
for (let i = 0; i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)
}
//变式
for (var i = 0; i< 10; i++){
let a = i;
setTimeout(() => {
console.log(a);
}, 1000)
}

解法二:大多数前端曾接触过的第一种方法——IIFE(立即执行函数)

for(var i = 0; i < 10; i++){
(function(i){
setTimeout(() => {
console.log(i);
},1000)
})(i);
}

解法三:比较优雅的做法——setTimeout可以接收多个参数

//setTimeout的函数签名是setTimeout(fn, delay, ...params),params会作为fn执行时的实参传入
for (var i = 0; i< 10; i++){
setTimeout((i) => {
console.log(i);
}, 1000, i);
}

解法四:利用函数方法bind为setTimeout传入预设参数

/*Function.prototype.bind(thisArg, ...args)
* 会得到一个新函数,新函数执行时预先设置了this和一部分参数,相当于把setTimeout改造成了偏函数
* bind执行后,setTimeout的第一个参数仍然是一个函数。
*/
for (var i = 0; i < 10; i++){
setTimeout(((i) => {
console.log(i);
}).bind(null,i), 1000);
}

解法五:利用禁术with

with的作用是延长作用域链会在词法作用域末端继续添加参数定义,在正式开发中通常是禁用的。下图右侧的scope一栏中就可以看到local作用域之上又多了一个with引入的作用域,其中就包含传入的i值。

for(var i = 0; i < 10; i++){
with({i}){
setTimeout(() => { console.log(i); },1000)
}
}

解法六:利用Promise传递决议结果来隔离作用域

//在每一轮循环中的i作为实参传递给promise的onFinished函数实现作用域隔离
for(var i = 0; i < 10; i++){
new Promise((resolve,reject)=>{
resolve(i);
}).then((i)=>{
setTimeout(() => { console.log(i); },1000)
}).catch(err=>{
console.log(err);
})
}

解法七:利用try...catch来隔离作用域

for(var i = 0; i < 10; i++){
try{
throw i;
}catch(i){
setTimeout(() => { console.log(i); },1000)
}
}

解法八:浏览器环境下setTimeout第一个参数可以为undefined(node.js中会报错)

//console.log相当于同步运行,跟setTimeout实际没什么关系了
for (var i = 0; i< 10; i++){
setTimeout(
console.log(i)
, 1000)
}

解法九:篡改console.log

let result = [];
let consoleLog = console.log;
console.log = (n)=> {
result.push(n);
if(result.length === 10) result.map((i,id)=>consoleLog(id));
} for(var i = 0; i < 10; i++){
setTimeout(() => {
console.log(i);
},1000)
} //变式——稍微有点欠扁
console.log = (function(){
let consoleLog = console.log;
let i = 0;
return n => i++ === 9 && consoleLog('0,1,2,3,4,5,6,7,8,9');
})(); for(var i = 0; i < 10; i++){
setTimeout(() => {
console.log(i);
},1000)
}

解法十:不按套路出牌的骚操作

for (var i = 0; i < 10; i++){
setTimeout(() => {
console.log(i++ % 10);
}, 1000);
} //变式
for (var i = 0; i < 10; i++){
setTimeout(() => {
console.log(i++);
}, 1000);
}
i = 0;

javascript基础修炼(13)——记一道有趣的JS脑洞练习题的更多相关文章

  1. javascript基础修炼(13)——记一道有趣的JS脑洞练习题【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  2. javascript基础修炼(5)—Event Loop(Node.js)

    开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 一道考察异步知识的面试题 题目是这样的,要求写出下面代码的输出: setTimeout(() => { co ...

  3. javascript基础修炼(2)——What's this(上)

    目录 一.this是什么 二.近距离看this 三. this的一般指向规则 四. 基本规则示例 五. 后记 开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一.thi ...

  4. javascript基础修炼(4)——UMD规范的代码推演

    javascript基础修炼(4)--UMD规范的代码推演 1. UMD规范 地址:https://github.com/umdjs/umd UMD规范,就是所有规范里长得最丑的那个,没有之一!!!它 ...

  5. javascript基础修炼(7)——Promise,异步,可靠性

    开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 别人是开发者,你也是 Promise技术是[javascript异步编程]这个话题中非常重要的,它一度让我感到熟悉 ...

  6. javascript基础修炼(8)——指向FP世界的箭头函数

    一. 箭头函数 箭头函数是ES6语法中加入的新特性,而它也是许多开发者对ES6仅有的了解,每当面试里被问到关于"ES6里添加了哪些新特性?"这种问题的时候,几乎总是会拿箭头函数来应 ...

  7. javascript基础修炼(10)——VirtualDOM和基本DFS

    1. Virtual-DOM是什么 Virtual-DOM,即虚拟DOM树.浏览器在解析文件时,会将html文档转换为document对象,在浏览器环境中运行的脚本文件都可以获取到它,通过操作docu ...

  8. javascript基础修炼(11)——DOM-DIFF的实现

    目录 一. 再谈从Virtual-Dom生成真实DOM 二. DOM-Diff的目的 三. DOM-Diff的基本算法描述 四. DOM-Diff的简单实现 4.1 期望效果 4.2 DOM-Diff ...

  9. javascript基础修炼(1)——一道十面埋伏的原型链面试题

    在基础面前,一切技巧都是浮云. 题目是这样的 要求写出控制台的输出. function Parent() { this.a = 1; this.b = [1, 2, this.a]; this.c = ...

随机推荐

  1. HDU - 3966 树链刨分

    题目传送门 操作就是询问某个点的值, 然后就是对一条路径上的值全部修改. 最基本的树刨题目了. 树刨的思想: 1. 对于每个点找到他的重儿子. void dfs1(int o, int u){ sz[ ...

  2. Heron and His Triangle 2017 沈阳区域赛

    A triangle is a Heron’s triangle if it satisfies that the side lengths of it are consecutive integer ...

  3. 【Offer】[26] 【树的子结构】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入两棵二叉树A和B,判断B是不是A的子结构.图中右边的树是左边的子结构  思路分析 先对树A进行遍历,找到与树B的根结点值相同的节点 ...

  4. CSAPP DataLab

    注意不同版本的题目可能会有所不同,搜了很多他们的题目和现在官网给的实验题都不一样,自己独立思考完整做一遍顺便记录一下. PS:这些难度为1的题有的说实话我都做了挺久的,不过完整做一遍感觉很有意思,这些 ...

  5. application.properties 乱码 (已验证)

    1.打开Eclipse或MyEclipse 2.选择window-Preferences-content Types-Text-Java Properties File 3.将Java Propert ...

  6. ubuntu修改中文文件夹名字为英文

    为了使用起来方便,装了ubuntu中文版,自然在home文件里用户目录的“桌面”.“图片”.“视频”.“音乐”……都是中文的. 很多时候都喜欢在桌面上放一些要操作的文件,Linux里命令行操作又多,难 ...

  7. js 中 undefined、NaN、null

    undefined 即未定义 js 中 没有声明 或者 声明后未赋值的变量 用typeof判断后类型都是 undefined 但是直接console.log( ) 输出的话 没有声明的变量会报错:而声 ...

  8. Linux 笔记 - 第十九章 配置 Squid 正向代理和反向代理服务

    一.简介 Squid 是一个高性能的代理缓存服务器,对应中文的乌贼,鱿鱼的意思.Squid 支持 FTP,gopher 和 HTTP 协议.和一般的代理缓存软件不同,Squid 用一个单独的,非模块化 ...

  9. Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析

    什么是心跳机制? 心跳说的是在客户端和服务端在互相建立ESTABLISH状态的时候,如何通过发送一个最简单的包来保持连接的存活,还有监控另一边服务的可用性等. 心跳包的作用 保活Q:为什么说心跳机制能 ...

  10. 【linux】【FastDFS】FastDFS上传返回的url直接下载和下载文件的文件名问题

    FastDFS安装及其他问题参考:https://www.cnblogs.com/jxd283465/p/11556263.html直接调用FastDFS返回的url,浏览器访问后默认打开方式./us ...