# JS 数据类型

# 原始数据类型

在 JS 中,存在着 6 种原始数据类型,分别是:

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

# 引用数据类型:

对象Object

  • 包含普通对象-Object,数组对象-Array,正则对象-RegExp,日期对象-Date,数学函数-Math,函数对象-Function

# null是对象吗

  • 回答: null不是对象。
  • 解释: 虽然 typeof null 会输出 object,但是这只是 JS 存在的一个悠久 Bug。
    • 在 JS 的最初版本中,为了性能,使用低位存储变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。

# 类型判断的方法

# typeof

typeof xxx得到的值有以下几种类型:undefined boolean number string object functionsymbol

这里需要注意几点:

  • typeof null结果是object ,实际这是typeof的一个bug,null是原始值,非引用类型
  • typeof [1, 2]结果是object,结果中没有array这一项,引用类型除了function其他的全部都是object
  • typeof Symbol()typeof获取symbol类型的值得到的是symbol,这是 ES6 新增的知识点

对于原始类型来说,除了 null 都可以调用typeof显示正确的类型。

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
1
2
3
4
5

但对于引用数据类型,除了函数之外,都会显示"object"。

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
1
2
3

因此采用 typeof 判断对象数据类型是不合适的

# instanceof

instanceof 运算符用于检测某个构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

  • 语法
  • object instanceof constructor
  • 参数
  • object 某个实例对象
  • constructor 某个构造函数

# 原始类型 vs 引用类型

# 对象类型和原始类型的不同之处

  • 原始类型存储的是值,
  • 对象类型存储的是地址(指针)。
  • 当创建一个对象类型的时候,将它分配到堆空间里面,分配后该对象会有一个在“堆”中的地址,然后再将该数据的地址写 进 该对象 的变量值。
  • 如果将变量赋值给另外一个变量时,复制的是原本变量的地址(指针),当进行数据修改的时候,就会修改存放在地址(指针)上的值,也就导致了两个变量的值都发生了改变。
11-原始类型-堆空间

# 具体分析

function foo(a){
    a = a * 10;
}
function bar(b){
    b.value = 'new';
}
var a = 1;
var b = {value: 'old'};
foo(a);
bar(b);
console.log(a); // 1
console.log(b); // value: new

1
2
3
4
5
6
7
8
9
10
11
12
13

通过代码执行,会发现:

  • a的值没有发生改变
  • b的值发生了改变

这就是因为Number类型的a是按值传递的,而Object类型的b是按共享传递的。

JS 中这种设计的原因是:按值传递的类型,复制一份存入栈内存,这类类型一般不占用太多内存,而且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会因为不停复制内容而造成内存的浪费。

// 说出下面运行的结果,并解释原因。
function test(person) {
  person.age = 26
  person = {
    name: lin,
    age: 18
  }
  return person
}
const p1 = {
  name: 'cherry',
  age: 19
}
const p2 = test(p1)
console.log(p1) 
console.log(p2) 
/* 结果:
p1:{name: “cherry”, age: 26}
p2:{name: “lin”, age: 18} */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

原因:

  • 在函数传参的时候传递的是对象在堆中的内存地址值,
  • test 函数中的实参 person 是 p1 对象的内存地址,通过调用 person.age = 26 确实改变了 p1 的值,
  • 但随后 person 变成了另一块内存空间的地址,并且在最后将这另外一份内存空间的地址返回,赋给了 p2 。

# 面试题

# 0.1+0.2为什么不等于0.3?

  • 0.1和0.2在转换成二进制后会无限循环,
  • 由于标准位数的限制 后面 多余的位数会被截掉,此时就已经出现了精度的损失,
  • 相加后 再将其转换为 十进制 就会变成0.30000000000000004。

# '1'.toString()为什么可以调用?

其实在这个语句运行的过程中做了这样几件事情:

var s = new Object('1');
s.toString();
s = null;
1
2
3
  • 第一步: 创建Object类实例。
  • 注意为什么不是String ? 由于Symbol和BigInt的出现,对它们调用new都会报错,目前ES6规范也不建议用new来创建基本类型的包装类。
  • 第二步: 调用实例方法。
  • 第三步: 执行完方法立即销毁这个实例。

【回答】

  • 在这种情况下,'1' 已经不是原始类型了,而是被强制转换成了 String 类型也就是对象类型,所以可以调用 toString 函数。

【什么是基本包装类型】

  • 三种原始类型的值——数值、字符串、布尔值——在一定条件下,也会自动转为对象,也就是原始类型的“包装对象”(wrapper)。
  • 所谓“包装对象”,指的是与数值、字符串、布尔值分别相对应的Number、String、Boolean三个原生对象。
  • 这三个原生对象可以把原始类型的值变成(包装成)对象。

# JS数据类型转换

# JS中类型转换有哪几种?

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

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

# == 和 ===有什么区别?

  • ===叫做严格相等,是指:左右两边不仅值要相等,类型也要相等,例如'1'===1的结果是false,因为一边是string,另一边是number。
  • ==不像===那样严格,对于一般情况,只要值相等,就返回true,
  • ==涉及一些类型转换,它的转换规则如下:
  • 首先会判断两者类型是否相同。相同的话就是比大小了
  • 类型不相同的话,那么就会进行类型转换
  • 会先判断是否在对比 null 和 undefined,是的话就会返回 true
  • 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
  • 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
  • 判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断
类型转换

# 判断 [] == ![] 的结果

  • 结果为true
  • 解析:
  • == 中,左右两边都需要转换为数字然后进行比较。
  • []转换为数字为0。
  • ![] 首先是转换为布尔值,由于[]作为一个引用类型转换为布尔值为true,
  • 因此![]为false,进而在转换成数字,变为0。
  • 0 == 0 , 结果为true

# 对象转原始类型是根据什么流程运行的?

对象转原始类型,会调用内置的[ToPrimitive]函数,对于该函数而言,其逻辑如下:

  1. 如果Symbol.toPrimitive()方法,优先调用再返回
  2. 调用valueOf(),如果转换为原始类型,则返回
  3. 调用toString(),如果转换为原始类型,则返回
  4. 如果都没有返回原始类型,会报错
var obj = {
  value: 3,
  valueOf() {
    return 4;
  },
  toString() {
    return '5'
  },
  [Symbol.toPrimitive]() {
    return 6
  }
}
console.log(obj + 1); // 输出7
1
2
3
4
5
6
7
8
9
10
11
12
13

# 如何让if(a == 1 && a == 2)条件成立?

var a = {
	value: 1,
	valueOf: function() {
		return this.value++
	}
}
console.log(a == 1 && a == 2) //true
1
2
3
4
5
6
7
上次更新: 2021年10月30日星期六晚上8点03分