自测

自我检测, 以下语法是否已经熟记

  1. 声明变量

  2. 修改变量的值

  3. 加减乘除取余

  4. 比较大小

  5. 逻辑运算判断

  6. if语句

  7. for语句

  8. whileswitch三元运算符

  9. 数组的基本使用语法

  10. 遍历数组

  11. 封装函数

  12. 对象的基本使用语法

  13. 遍历对象

1. 数据类型

涉及面试题:原始类型有哪几种?null 是对象嘛?
涉及面试题:对象类型和原始类型的不同之处?函数参数是对象会发生什么问题?

原始类型(基本类型)

在 JS 中,存在着 6 种原始值,分别是:

  • boolean
  • null
  • undefined
  • number
  • string
  • symbol

对于 null 来说,很多人会认为他是个对象类型,其实这是错误的。虽然 typeof null 会输出 object,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。

引用类型(对象类型)

在 JS 中,除了原始类型那么其他的都是对象类型了(数组、函数都是对象)。

对象类型和原始类型不同的是,原始类型存储的是值,对象类型存储的是地址(指针)。

当你创建了一个对象类型的时候,计算机会在内存中帮我们开辟一个空间来存放值,但是我们需要找到这个空间,这个空间会拥有一个地址(指针)。

当我们将保存对象的变量赋值给另外一个变量时,复制的只是原本变量的地址(指针),当我们进行数据修改的时候,就会修改存放在地址(指针)上的值,也就导致了两个变量的值都发生了改变。

参数是函数的情况:

function test(person) {
  person.age = 26

  //person = {
  //  name: 'yyy',
  //  age: 30
  //}
  //上句代码相当于为person分配了一个对象,此时person修改时,就不会影响变量 p1

  return person
}
const p1 = {
  name: '张三',
  age: 25
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?
  • 首先,函数传参是传递对象指针的副本
  • 到函数内部修改参数的属性这步,我相信大家都知道,当前 p1 的值也被修改了

2. 为什么 0.1 + 0.2 != 0.3

涉及面试题:为什么 0.1 + 0.2 != 0.3?如何解决这个问题?

先说原因,因为 JS 采用 IEEE 754 双精度版本(64位),并且只要采用 IEEE 754 的语言都有该问题。

我们都知道计算机是通过二进制来存储东西的,那么 0.1 在二进制中会表示为

// (0011) 表示循环
0.1 = 2^-4 * 1.10011(0011)

我们可以发现,0.1 在二进制中是无限循环的一些数字,其实不只是 0.1,其实很多十进制小数用二进制表示都是无限循环的。这样其实没什么问题,但是 JS 采用的浮点数标准却会裁剪掉我们的数字。

IEEE 754 双精度版本(64位)将 64 位分为了三段

  • 第一位用来表示符号
  • 接下去的 11 位用来表示指数
  • 其他的位数用来表示有效位,也就是用二进制表示 0.1 中的 10011(0011)

那么这些循环的数字被裁剪了,就会出现精度丢失的问题,也就造成了 0.1 不再是 0.1 了,而是变成了 0.100000000000000002

0.100000000000000002 === 0.1 // true

那么同样的,0.2 在二进制也是无限循环的,被裁剪后也失去了精度变成了 0.200000000000000002

0.200000000000000002 === 0.2 // true

所以这两者相加不等于 0.3 而是 0.300000000000000004

0.1 + 0.2 === 0.30000000000000004 // true

那么可能你又会有一个疑问,既然 0.1 不是 0.1,那为什么 console.log(0.1) 却是正确的呢?

因为在输入内容的时候,二进制被转换为了十进制,十进制又被转换为了字符串,在这个转换的过程中发生了取近似值的过程,所以打印出来的其实是一个近似值,你也可以通过以下代码来验证

console.log(0.100000000000000002) // 0.1

最后来说说怎么解决这个问题吧。其实解决的办法有很多,这里我们选用原生提供的方式来最简单的解决问题

parseFloat((0.1 + 0.2).toFixed(10)) === 0.3 // true

3. 类型转换

首先我们要知道,在 JS 中类型转换只有三种情况,分别是:

  • 转换为布尔值
  • 转换为数字
  • 转换为字符串

4. this

涉及面试题:如何正确判断 this?箭头函数的 this 是什么?

this 是很多人会混淆的概念,但是其实它一点都不难,只是网上很多文章把简单的东西说复杂了。

function foo() {
  console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo: foo
}
obj.foo()

const c = new foo()

接下来我们一个个分析上面几个场景

  • 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window
  • 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象
  • 对于 new 的方式来说,this 被永远绑定在了 c 上面,不会被任何方式改变 this

== vs ===

涉及面试题:== 和 === 有什么区别?

对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换

假如我们需要对比 x 和 y 是否相同,就会进行如下判断流程:

  • 首先会判断两者类型是否相同。相同的话就是比大小了
  • 类型不相同的话,那么就会进行类型转换
  • 会先判断是否在对比 null 和 undefined,是的话就会返回 true
  • 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
1 == '1'
      ↓
1 ==  1

判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断

'1' == true'1' ==  1
        ↓
 1  ==  1

判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断

'1' == { name: '张三' }
        ↓
'1' == '[object Object]'

对于 === 来说就简单多了,就是判断两者类型和值是否相同。

文档更新时间: 2022-04-27 17:40   作者:张老师