# 变量类型

# 原始类型

6 种原始类型:Boolean、String、Number、Null、Undefined、Symbol(ES6 新定义)。

原始类型存储的都是值,是没有函数可以调用的。但是'1'.toString()是可以使用的。其实在这种情况下,'1'已经不是原始类型了,而是被强制转换成了 String 类型也就是对象类型,所以可以调用 toString 函数。

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

理解和使用ES6中的Symbol

# 对象类型

在 JS 中,除了原始类型那么其他的都是对象类型了。原始类型存储的是值,对象类型存储的是地址。

函数参数是对象的情况:

function test(person) {
  person.age = 26
  person = {
    name: 'yyy',
    age: 30
  }

  return person
}
const p1 = {
  name: 'jack',
  age: 25
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 首先,函数传参是传递对象指针的副本
  • 到函数内部修改参数的属性这步,我相信大家都知道,当前 p1 的值也被修改了
  • 但是当我们重新为 person 分配了一个对象时就出现了分歧,请看下图

image

所以最后 person 拥有了一个新的地址(指针),也就和 p1 没有任何关系了,导致了最终两个变量的值是不相同的。

# typeof VS instanceof

typeof 对于原始类型来说,除了 null(null显示为Object) 都可以显示正确的类型。

typeof 对于对象来说,除了函数(函数显示为function)都会显示object,所以说 typeof 并不能准确判断变量到底是什么类型。

想判断一个对象的正确类型,这时候可以考虑使用instanceof,因为内部机制是通过原型链来判断的。

# 类型转换

在 JS 中类型转换只有三种情况,分别是:

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

image

对象转原始类型:

  • 转字符串类型就调用 x.toString()
  • 转基础类型就调用 x.valueOf()

当然你也可以重写 Symbol.toPrimitive,该方法在转原始类型时调用优先级最高。

let a = {
  valueOf() {
    return 0
  },
  toString() {
    return '1'
  },
  [Symbol.toPrimitive]() {
    return 2
  }
}
console.log(1 + a) // => 3
1
2
3
4
5
6
7
8
9
10
11
12

# 相等运算符的规则

[] == []为false,[] == ![]为true

相等运算符的运算规则如下:

1、如果两个值类型相同,进行 === 比较。

2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:

(1)如果一个是null、一个是undefined,那么[相等]。

(2)如果任一值是字符串,另一个值是数值,在比较相等性之前先将字符串转换为数值;即是调用Number()函数。

(3)如果任一值是布尔值,则在比较相等性之前先将其转换为数值,即是调用Number()函数。

(4)如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。 js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。

再次分析 [ ] == ![ ]这道题:

(1)看见 ![ ]这个是要对空数组转成布尔类型结果得到![ ] = false,

(2)发现此时符合第三条,如果任一值是布尔类型是需要将其转换为数值,即Number(false),结果为 Number(false) = 0。

(3)此时得到 [ ] == 0比较,此时符合第四条 即 [ ].toString();结果为[].toString() = ” ”;

(4)此时得到 ” ” == 0,发现符合第二条即Number(“”); 结果为Number(” ”) = 0;n

(5)此时得到 0 == 0 两个同时为数值类型比较所以结果为true;

需要注意的是,数组会先通过调用toString()转换为字符串后再转换为数值,比如[true]转换为字符串后为"true",然后再转换为数值是NaN,所以[true]==1返回false。

事实上,数组、对象和函数在与其他基本数据类型进行比较时都会先转换为字符串,然后再转换为相应的数据类型.

参考

Last Updated: 4/12/2020, 3:36:17 PM