javascript重难点,7个简单而又容易犯错的JavaScript知识点
javascript重难点,7个简单而又容易犯错的JavaScript知识点在 one() 范围或全局范围中都没有声明变量b。因此JavaScript将 b = 0 表达式解释为window.b = 0。换句话说,b是被意外创建的全局变量。第3行:let a = b = 0,该语句声明一个局部变量a,但是,它也声明了全局变量b。下面就来讲讲究竟是哪7个知识点让我又爱又恨呢?上述代码中,运行 typeof a 和 typeof b,会输出什么呢?
最近在做项目,负责写前端,就避免不了要和JavaScript打交道,但总是因为有些知识点没有真正掌握,老是采坑,甚是浪费时间,故此记录下来便于自己“复习”,或许也可以解决新手程序员的疑惑(如文章有错误,欢迎老手们指点指点,让我也快快成为一名没有头发的老手,哈哈哈)
这次讲解就基于“JSRUN”这个代码调试网站来讲解
JSRUN
下面就来讲讲究竟是哪7个知识点让我又爱又恨呢?
被意外创建的全局变量- 问题
上述代码中,运行 typeof a 和 typeof b,会输出什么呢?
- 答案
第3行:let a = b = 0,该语句声明一个局部变量a,但是,它也声明了全局变量b。
在 one() 范围或全局范围中都没有声明变量b。因此JavaScript将 b = 0 表达式解释为window.b = 0。换句话说,b是被意外创建的全局变量。
所以,输出的结果为
结果
typeof a 等于 'undefined',变量 a 存在于 one() 范围内,而在外部范围内不使用。因为变量b是一个值为0的全局变量,所以b的类型的值为 'number'。其实,上述代码等同于:
数组的length属性- 问题
clothes[0] 的值是什么呢?
问题
- 答案
运行结果
数组对象的 length 属性具有特殊的行为:减少length属性的值就是删除在自己的元素。因此,当JavaScript执行 clothes.length = 0 的时候将删除所有元素。
因为 clothes 数组已被清空,所以clothes [0] 等于 undefined
手动插入分号- 问题
numbers 数组的内容是什么?
让我们仔细看一下第四行的分号 ; 出现在左大括号 { 前面
这个分号很容易被忽略,它创建了一个空语句。空语句是不做任何事情的空语句。for() 在空语句上进行4次迭代(不执行任何操作),而忽略实际将项目插入数组的块 {number.push(i 1);}
运行结果
上面的代码等效于以下代码:
for() 将 i 变量递增到4(即 i=4 ),然后往下执行一次块 {number.push(i 1);},将 4 1 插入数组。所以,numbers 数组的内容为 [5]。
自动分号插入- 问题
four() 返回什么值?
- 答案
一眼看上去,那么简单,结果不就是 [10] 吗?但结果却出乎意料,因为我们都错过了 return 关键字和 [item] 表达式之间的换行符。此换行符会让JavaScript自动在return 和 [item] 表达式之间插入分号。这是等效的代码,在返回后插入了分号:
运行结果
return; 就相当于结束了函数,后面的 [item] 不会被执行,所以函数没有返回任何东西。因此 four(10) 的值为 undefined。
“辣手”的闭包- 问题
以上代码输出什么?
- 答案
如果您以前从未听说过闭包,那么,则很可能您的答案想当然是 0、1 和 2,但这是错误的(我一次也踩雷了)。
执行此代码段有两个阶段。
阶段一(发生在100ms之前):
- for() 重复3次,在每次迭代过程中,都会创建一个新的函数 log() 来捕获变量 i。然后 setTimout() 延时100毫秒执行log()。
- 当 for() 循环完成时(此时log()函数一次都没有被执行),i 变量的值为 3。
log() 是一个捕获变量 i 的闭包,该变量在 for() 循环的外部范围中定义。请务必注意,闭包可以词法捕获 i 变量。
阶段二(发生在100ms之后):
- setTimeout() 调用了3次 log() 。log() 读取变量i的当前值为3,所以这就是输出为3、3 和 3 的原因。
- 问题
这个等式的结果是什么呢?
- 答案
首先,让我们看一下 0.1 0.2 的值:
0.1 和 0.2 的总和不完全是 0.3,而是略高于 0.3。
- 原因
我们站在计算机的角度去思考问题,0.1 0.2 这个看似简单的问题,众所周知,能被计算机读懂的是二进制,而不是我们经常看见的十进制,所以我们先把0.1 0.2转换为十进制,
0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)
双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。因此像浮点数相加之类的操作会产生舍入误差。
简而言之,直接比较浮点数是并不精确。因此 0.1 0.2 === 0.3 的结果是 false。
那么,如何才能得到0.3呢?方法很简单,先将各个浮点数乘以 10的N次方 再将最后的结果除以 10的N次方 就可以了。
变量提升- 问题
如果在声明前访问 myVar 和 myconst,会发生什么情况?
- 答案
在JavaScript变量生命周期中,有两个重要概念,提升和临时性死区。
- 变量提升
var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。所以图一的代码等同于:
但图二中,变量 myConst 用 const 命令声明,不会发生变量提升。这表示在声明它之前,变量myConst 是不存在的,这时如果用到它,就会抛出一个错误。
- 暂时性死区
在 let 和 const 中还存在一个叫做 “临时性死区” 的概念。在这个作用域的开始直到变量的声明之前,这个变量都是处在 “临时性死区” 当中的,这个时候引用他的话会报 referenceError 的错误
ES6 明确规定,如果区块中存在 let 和 const 命令,这个区块对let 和 const 命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
附加题:
var tmp = 123;
if (true) {
tmp = 'abc'; // => ???
let tmp;
}
那上述这段代码中tmp的值是多少呢?还是会报 referenceError 的错误?欢迎各位小伙伴在评论区留下您们的答案吧,一起共同进步,哈哈哈!
至此,7个又爱又恨的知识点就已经介绍完了,如有问题,欢迎各位大神指正!谢谢!