JS基础——数据类型(一)
Tao. Lv2

一、基本概念

1.类型分类?

js 一共有七种基本数据类型,分别是

  • Undefined

  • Null

  • Boolean

  • Number

  • String

  • Symbol

  • BigInt

Symbol是ES6新增的类型,代表创建后独一无二且不可变的数据类型,它的出现主要是为了解决可能出现的全局变量冲突的问题。详情可参考:ES6-Symbol

BigInt是ES10新增的类型。BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。

引用数据类型:

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

2.null和undefined的区别

首先 Undefined 和 Null 都是基本数据类型。

undefined 代表的含义是未定义(值),null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。

undefined 在 js 中不是一个保留字,这意味着我们可以使用 undefined 来作为一个变量名,这样的做法是非常危险的,它会影响我们对 undefined 值的判断。但是我们可以通过一些方法获得安全的 undefined 值,比如说 void 0

当我们对两种类型使用 typeof 进行判断的时候,Null 类型化会返回 “object”

1
typeof null //  'object' 

这是一个历史遗留的问题,在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object 。

当我们使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。

参考《JavaScript 深入理解之 undefined 与 null》

http://cavszhouyou.top/JavaScript%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E4%B9%8Bundefined%E4%B8%8Enull.html

3.”666”.toString()为什么可以调用

基本包装类型:

基本类型值不是对象,从逻辑上讲它们不应有方法。

但实际上当读取一个基本类型值时,后台会创建一个对应的基本包装类型的对象

回到题目:

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

1
2
3
var s = new Object('666');
s.toString();
s = null;

第一步: 创建Object类实例。注意为什么不是String ? 由于Symbol和BigInt的出现,对它们调用new都会报错,目前ES6规范也不建议用new来创建基本类型的包装类。

第二步: 调用实例方法。

第三步: 执行完方法立即销毁这个实例。

整个过程体现了基本包装类型的性质,而基本包装类型恰恰属于基本数据类型,包括Boolean, Number和String。

上面例子相当于隐式装箱,详情见JS基础——数据类型(二)

4.0.1+0.3 != 0.3?

JS默认数字都是隐式采用IEEE 754二进制运算的

二进制只能精准表达2除尽的数字1/2, 1/4, 1/8,例如0.1(1/10)和0.2(1/5),在二进制中都无法精准表示时,需要根据精度舍入。

我们人类熟悉的十进制运算系统,可以精准表达2和5除尽的数字,例如1/2, 1/4, 1/5(0.2), 1/8, 1/10(0.1)。

当然十进制也有无法除尽的地方,例如1/3, 1/7,也需要根据精度舍入。

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

如何使它相等?

方法一:

乘倍数得到整数,再除以原来的倍数

1
(0.1*10+0.2*10)/10 ===0.3

方法二:

1
parseFloat((0.1+0.2).toFixed(10)) ===0.3

二、判断方式

1.typeof

对于基本数据类型来说,除了 null 都可以调用typeof显示正确的类型

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

因此采用typeof判断对象数据类型是不合适的,采用instanceof会更好,instanceof的原理是基于原型链的查询,只要处于原型链中,判断永远为true

1
2
3
4
5
6
7
8
9
const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true

var str1 = 'hello world'
str1 instanceof String // false

var str2 = new String('hello world')
str2 instanceof String // true

2.instance

基于原型链上查找

1
2
3
4
5
6
7
8
9
10
11
12
13
function myInstanceof(left, right) {
//基本数据类型直接返回false
if(typeof left !== 'object' || left === null) return false;
//getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象
let proto = Object.getPrototypeOf(left);
while(true) {
//查找到尽头,还没找到
if(proto == null) return false;
//找到相同的原型对象
if(proto == right.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}

Object.getPrototypeOf获取实例对象的__ proto __属性,判断实例对象的原型是否等于构造函数的原型(prototype)

Object.getPrototypeOf:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/GetPrototypeOf

缺点:未考虑传入function情况