快捷搜索:  汽车  科技

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”这个代码调试网站来讲解

javascript重难点,7个简单而又容易犯错的JavaScript知识点(1)

JSRUN

下面就来讲讲究竟是哪7个知识点让我又爱又恨呢?

被意外创建的全局变量
  • 问题

javascript重难点,7个简单而又容易犯错的JavaScript知识点(2)

上述代码中,运行 typeof atypeof b,会输出什么呢?

  • 答案

第3行:let a = b = 0,该语句声明一个局部变量a,但是,它也声明了全局变量b。

one() 范围或全局范围中都没有声明变量b。因此JavaScript将 b = 0 表达式解释为window.b = 0。换句话说,b是被意外创建的全局变量。

所以,输出的结果为

javascript重难点,7个简单而又容易犯错的JavaScript知识点(3)

结果

typeof a 等于 'undefined',变量 a 存在于 one() 范围内,而在外部范围内不使用。因为变量b是一个值为0的全局变量,所以b的类型的值为 'number'。其实,上述代码等同于:

javascript重难点,7个简单而又容易犯错的JavaScript知识点(4)

数组的length属性
  • 问题

clothes[0] 的值是什么呢?

javascript重难点,7个简单而又容易犯错的JavaScript知识点(5)

问题

  • 答案

javascript重难点,7个简单而又容易犯错的JavaScript知识点(6)

运行结果

数组对象的 length 属性具有特殊的行为:减少length属性的值就是删除在自己的元素。因此,当JavaScript执行 clothes.length = 0 的时候将删除所有元素。

因为 clothes 数组已被清空,所以clothes [0] 等于 undefined

手动插入分号
  • 问题

javascript重难点,7个简单而又容易犯错的JavaScript知识点(7)

numbers 数组的内容是什么?

让我们仔细看一下第四行的分号 出现在左大括号 { 前面

这个分号很容易被忽略,它创建了一个空语句。空语句是不做任何事情的空语句。for() 在空语句上进行4次迭代(不执行任何操作),而忽略实际将项目插入数组的块 {number.push(i 1);}

javascript重难点,7个简单而又容易犯错的JavaScript知识点(8)

运行结果

上面的代码等效于以下代码:

javascript重难点,7个简单而又容易犯错的JavaScript知识点(9)

for() 将 i 变量递增到4(即 i=4 ),然后往下执行一次块 {number.push(i 1);},将 4 1 插入数组。所以,numbers 数组的内容为 [5]

自动分号插入
  • 问题

javascript重难点,7个简单而又容易犯错的JavaScript知识点(10)

four() 返回什么值?

  • 答案

一眼看上去,那么简单,结果不就是 [10] 吗?但结果却出乎意料,因为我们都错过了 return 关键字和 [item] 表达式之间的换行符。此换行符会让JavaScript自动在return[item] 表达式之间插入分号。这是等效的代码,在返回后插入了分号:

javascript重难点,7个简单而又容易犯错的JavaScript知识点(11)

javascript重难点,7个简单而又容易犯错的JavaScript知识点(12)

运行结果

return; 就相当于结束了函数,后面的 [item] 不会被执行,所以函数没有返回任何东西。因此 four(10) 的值为 undefined

“辣手”的闭包
  • 问题

javascript重难点,7个简单而又容易犯错的JavaScript知识点(13)

以上代码输出什么?

  • 答案

如果您以前从未听说过闭包,那么,则很可能您的答案想当然是 0、1 和 2,但这是错误的(我一次也踩雷了)。

执行此代码段有两个阶段。

阶段一(发生在100ms之前):

  1. for() 重复3次,在每次迭代过程中,都会创建一个新的函数 log() 来捕获变量 i。然后 setTimout() 延时100毫秒执行log()。
  2. 当 for() 循环完成时(此时log()函数一次都没有被执行),i 变量的值为 3。

log() 是一个捕获变量 i 的闭包,该变量在 for() 循环的外部范围中定义。请务必注意,闭包可以词法捕获 i 变量。

阶段二(发生在100ms之后):

  1. setTimeout() 调用了3次 log()log() 读取变量i的当前值为3,所以这就是输出为3、3 和 3 的原因。

javascript重难点,7个简单而又容易犯错的JavaScript知识点(14)

浮点数计算
  • 问题

javascript重难点,7个简单而又容易犯错的JavaScript知识点(15)

这个等式的结果是什么呢?

  • 答案

首先,让我们看一下 0.1 0.2 的值:

javascript重难点,7个简单而又容易犯错的JavaScript知识点(16)

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次方 就可以了。

javascript重难点,7个简单而又容易犯错的JavaScript知识点(17)

变量提升
  • 问题

javascript重难点,7个简单而又容易犯错的JavaScript知识点(18)

javascript重难点,7个简单而又容易犯错的JavaScript知识点(19)

如果在声明前访问 myVar 和 myconst,会发生什么情况?

  • 答案

在JavaScript变量生命周期中,有两个重要概念,提升和临时性死区。

  • 变量提升

var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。所以图一的代码等同于:

javascript重难点,7个简单而又容易犯错的JavaScript知识点(20)

但图二中,变量 myConst const 命令声明,不会发生变量提升。这表示在声明它之前,变量myConst 是不存在的,这时如果用到它,就会抛出一个错误。

javascript重难点,7个简单而又容易犯错的JavaScript知识点(21)

  • 暂时性死区

let const 中还存在一个叫做 “临时性死区” 的概念。在这个作用域的开始直到变量的声明之前,这个变量都是处在 “临时性死区” 当中的,这个时候引用他的话会报 referenceError 的错误

javascript重难点,7个简单而又容易犯错的JavaScript知识点(22)

ES6 明确规定,如果区块中存在 letconst 命令,这个区块对letconst 命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。


附加题:

var tmp = 123;

if (true) {

tmp = 'abc'; // => ???

let tmp;

}

那上述这段代码中tmp的值是多少呢?还是会报 referenceError 的错误?欢迎各位小伙伴在评论区留下您们的答案吧,一起共同进步,哈哈哈!


至此,7个又爱又恨的知识点就已经介绍完了,如有问题,欢迎各位大神指正!谢谢!

猜您喜欢: