版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

【摘要】 开脑洞,也巩固基础知识

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

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

一. 题目

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

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

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

二. 解法风暴

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

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

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

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

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

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

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

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

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

解法五:利用禁术with

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

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

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

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

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

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

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

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

解法九:篡改console.log

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

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

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

作者:大史不说话

HDC.Cloud 华为开发者大会2020 即将于2020年2月11日-12日在深圳举办,是一线开发者学习实践鲲鹏通用计算、昇腾AI计算、数据库、区块链、云原生、5G等ICT开放能力的最佳舞台。

欢迎报名参会

javascript基础修炼(13)——记一道有趣的JS脑洞练习题【华为云技术分享】的更多相关文章

  1. javascript基础修炼(13)——记一道有趣的JS脑洞练习题

    目录 一. 题目 二. 解法风暴 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址 ...

  2. 【我的物联网成长记6】由浅入深了解NB-IoT【华为云技术分享】

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

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

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

  4. 【我的物联网成长记8】超速入门AT指令集【华为云技术分享】

    [摘要] 在物联网中,AT命令集可用于控制&调测设备.通信模块入网等.本文为您介绍NB-IoT常用的AT命令集及其调测工具. 什么是AT指令集 AT命令,用来控制TE(Terminal Equ ...

  5. 搞清楚一道关于Integer的面试题【华为云技术分享】

    请看题1: public class IntegerDemo { public static void main(String[] args) { Integer a = ; Integer b = ...

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

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

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

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

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

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

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

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

随机推荐

  1. CSPS模拟 69

    $C_n^0=1$ $C_n^0=1$ $C_n^0=1$ 我怎么又双叒叕犯这种错误了啊 (咳檀) T1 WA0,大神题,不会做! T2 就是要找一个最长区间,满足左端点是区间最小值,右端点是区间最大 ...

  2. Box 黑科技 —— 支持手机端反编译 !Box 黑科技 —— 支持手机端反编译 !

    项目地址: Box 文末扫码获取最新安装包 . 前言 有将近一个月没有更新文章了,一方面在啃 AOSP ,消化起来确实比较慢.在阅读的过程中,有时候上来就会陷入源码细节,其实这是没有必要的.刚开始更多 ...

  3. linux下安装opencv3.0

    查版本gcc --version 需>4.8python 2.7+cmake --version numpy 以上是必须的 linux下安装opencv3.0<pre>https:/ ...

  4. 深入理解 DNS

    深入理解 DNS 简介 DNS(Domain Name System)域名系统,它是一个将域名和 IP 地址相互映射的一个分布式数据库,把容易记忆的主机名转换成主机 IP 地址. DNS使用 TCP ...

  5. CSS 技巧一则 -- 在 CSS 中使用三角函数绘制曲线图形及展示动画

    最近一直在使用 css-doodle 实现一些 CSS 效果. css-doodle 是一个基于 Web-Component 的库.允许我们快速的创建基于 CSS Grid 布局的页面,以实现各种 C ...

  6. [ch02-00] 反向传播与梯度下降的通俗解释

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 第2章 神经网络中的三个基本概念 2.0 通俗地理解三大 ...

  7. 附010.Kubernetes永久存储之GlusterFS超融合部署

    一 前期准备 1.1 基础知识 在Kubernetes中,使用GlusterFS文件系统,操作步骤通常是: 创建brick-->创建volume-->创建PV-->创建PVC--&g ...

  8. windows 10 上源码编译OpenCV并支持CUDA | compile opencv with CUDA support on windows 10

    本文首发于个人博客https://kezunlin.me/post/6580691f/,欢迎阅读! compile opencv with CUDA support on windows 10 Ser ...

  9. mac中安装Jenkins+jdk

    Jenkins是基于Java开发的一种持续集成工具,用于持续的软件版本发布/测试项目,并监控外部调用执行的工作.简单来说就是自动化测试+部署. 首先我们需要安装jdk,注意,目前jenkins只支持j ...

  10. go中的关键字-go(上)

    1. goroutine的使用 在Go语言中,表达式go f(x, y, z)会启动一个新的goroutine运行函数f(x, y, z),创建一个并发任务单元.即go关键字可以用来开启一个gorou ...