博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一道JavaScript面试题
阅读量:6458 次
发布时间:2019-06-23

本文共 2021 字,大约阅读时间需要 6 分钟。

JavaScript面试题

题目

话不多说,直接上题! 下面代码的输出结果是什么?

var value1 = 0;var value2 = 0;var value3 = 0;for( var i = 10; i > 0; i-- ){    var i2 = i;    (function(){        var i3 = i;        setTimeout(function(){            value1 += i;            value2 += i2;            value3 += i3;        }, 1);    })();}setTimeout(function(){    console.log(value1, value2, value3);}, 100);复制代码

思考一下你的答案... 10 9 8 7 6 5 4 3 2 1

答案:

0 10 55复制代码

可能除了部分老前端,大部分人第一次见到这个题目都会答错。因为这行为太诡异了,不符合我们大部分编程语言的逻辑思维。尤其是咋们常年做后端的朋友们(包括我,一个年轻的后端),看到这输出,什么鬼??哈哈,不要惊慌,这可以说是由JavaScript的缺陷引起的,没错,缺陷!下面我们来分析一下为什么会出现这个诡异的输出。

解析

首先我们需要说一说关于var的两个特性:变量提升和没有块作用域。

什么是变量提升

其实很简单,脚本运行的时候,变量的声明会统一提升到作用域的头部。也就是说,脚本一运行所有的全局变量就已经声明了(但还有没有赋值)。举个例子

var v1 = 111;console.log(v2) // 不会报错,输出undefined// do some thing ....// a lot of codevar v2 = 222;复制代码

上面的代码运行时其实是下面的样子:

var v1;var v2;v1 = 111;console.log(v2); //没有报错而输出undefined,已经很明了了// do some thing ....// a lot of codev2 = 222;复制代码

块级作用域

对于var来说,是没有块级作用域的(有方法作用域啊)。也就是说,你可以在块外使用块内声明的变量。举个例子:

var flage = 1;if( flage ){    var innerValue = 111;}console.log(innerValue);复制代码

上面的代码不会报错,而会输出111。因为innerValue实际上是一个全局变量。它等价于下面的代码:

var flage;var innerValue;flage = 1;if( flage ){    innerValue = 111;}console.log(innerValue);复制代码

分析题目

现在,再回过头来看题目。就很好理解了,它实际运行时是下面的样子:

var value1 var value2;var value3;var i;var i2;value1 = 0;value1 = 0;value1 = 0;for( i = 10; i > 0; i-- ){    i2 = i;    (function(){        var i3 = i;        setTimeout(function(){            value1 += i;            value2 += i2;            value3 += i3;        }, 1);    })();}setTimeout(function(){    console.log(value1, value2, value3);}, 100);复制代码

变量i和i2,实际上是全局变量。 最后一次执行for循环时,很显然此时i的值是1,i2最终被赋值为1。 代码继续运行,i变成0,不满足循环条件,退出循环,i最终为0。 对于i3来说,它是一个函数内部变量,最终形成了一个闭包。每一次运行匿名函数都是一个新的变量,他的值则很正常的依次被赋予10 9 8 7 .... 1。 循环结束。开始执行timeout,value1被加上十个i (0),最终为0。 value2被加上十个i2 (1), 最终为10。 value3依次加上各自私有个i3,最终为55。 所以输出是 0 10 55。

题外话

为了解决刚才所说的var两个“缺陷”,es6引入了let。let 不允许在声明之前使用,有块级作用域。将题目中var 换为let之后, 程序将输出"不诡异"的结果:55 55 55

转载于:https://juejin.im/post/5c85255ce51d45192c4a6c3b

你可能感兴趣的文章
在用户控件中动态添加控件及事件
查看>>
垃圾收集趣史
查看>>
Servlet和JSP学习指南
查看>>
c#获取或修改配置文件
查看>>
Wps的ppt里 让图片按顺序出现 就是点击一下 出现一张照片
查看>>
hadoop的WordCount样例
查看>>
OpenCV】透视变换 Perspective Transformation(续)
查看>>
63. Unique Paths II
查看>>
WPF Visifire 图表控件
查看>>
linux下解压命令大全
查看>>
Java——设计模式(装饰模式_IO)
查看>>
一个简单版的波纹css3动画
查看>>
Web安全之Cookie劫持
查看>>
关于禁止ViewPager预加载问题【转】
查看>>
【iCore4 双核心板_uC/OS-II】例程八:消息邮箱
查看>>
Swift 泛型
查看>>
WPF自定义控件(四)の自定义控件
查看>>
Cocos2d-x中点九图(Scale9Sprite)创建图片按钮
查看>>
PC远程调试移动设备
查看>>
HDU 4819 Mosaic (二维线段树)
查看>>