JS数据类型及常见转换规则
数据类型
JS中的数据类型主要分为两大类:原始类型
和引用类型
。常见的数据类型如下图所示:
原始数据类型存在栈中,引用类型在栈中存的是一个引用地址,这个地址指向的是堆中的一个数据对象。需要注意的是
null
在这里我们算在原始类型里面,但是你用typeof
的时候会发现他是object
,原因是就算他是一个对象,那他应该在栈中存一个引用地址,但是他是一个空对象,所以这个地址为空,也就是不对应堆中的任意一个数据,他在堆中没有数据,只存在于栈中,所以这里算为了原始类型。引用类型其实主要就是Object
,Array
和Function
这些其实也都是Object
派生出来的。
原始类型
原始类型的值无法更改,要更改只能重新赋值,原始类型的比较就是比较值,值相等,他们就相等
引用类型
引用类型的值是可以修改的,修改后引用地址并没有变化,变化的是堆中的数据。
引用类型的比较是比较他们的索引地址,而不是他们的值。
要想让他们相等,得直接将b
赋值为a
,这样他们的引用地址一样,就是相等的。
类型转换
隐式类型转换
转为字符串
经常出现在+
运算中,并且其中有一个操作数不是数值类型
let s = 4 + 'px' + 5;
console.log(s); // 4px5
s = 123e-2 + 'a';
console.log(s); // 1.23a
复制代码
转为数值
经常出现在数学运算中,表示连接字符串的+
运算除外
let s = 'abc';
console.log(+s, -s); // NaN, NaN
s = ' 123 ';
console.log(+s, -s); // 123 -123
s = new Date();
console.log(+s, -s); // 1588675647421 -1588675647421 (这个操作相当于取毫秒数)
转为bool的场景
经常出现在if或者逻辑运算中
let s = 'abc';
if(s) {
console.log(s); // abc
}
console.log(!!s); // true
下面的值在进行bool转换时会转换为false
,除此以外都是true
:
- 0
- NaN
- ''(空字符串)
- null
- undefined
==运算符
当我们使用==
进行比较时,如果两边的类型不同,JS会进行类型转换,然后再比较,===
则不会进行类型转换,如果===
两边的数据类型不同,直接返回false
。
类型检测
类型检测是我们经常遇到的问题,面试时也经常问到各种类型检测的方法,下面是几种常用的类型检测的方法。
typeof
做类型检测最常用的就是typeof
了:
let a;
typeof a; // undefined
let b = true;
typeof b; // boolean
let c = 123;
typeof c; // number
let d = 'abc';
typeof d; // string
let e = () => {};
typeof e; // function
let f = {};
typeof f; // object
let g = Symbol();
typeof g; // symbol
instanceof
typeof
最简单,但是他只能判断基本的类型,如果是对象的话,没法判断具体是哪个对象。instanceof
可以检测一个对象是不是某个类的实例,这种检测其实基于面向对象和原型链的,更多关于instanceof原理的可以看这篇文章。下面来看个例子:
let a = new Date();
a instanceof Date; // true
let arr=[2]
arr instanceof Array //true
constructor
constructor
的原理其实跟前面的instanceof
有点像,也是基于面向对象和原型链的。一个对象如果是一个类的实例的话,那他原型上的constructor
其实也就指向了这个类,我们可以通过判断他的constructor
来判断他是不是某个类的实例。
Object.prototype.toString.call
Object.prototype.toString.call
是比较准确的,可以用来判断原生对象具体是哪个类型:
Object.prototype.toString.call(new Array()); // [object Array]
Object.prototype.toString.call(new Date()); // [object Date]
复制代码
这个方法返回的是[object XXX]
,这个XXX是对应的构造函数名字。但是他只能检测原生对象,对于自定义类型是没有用的:
function a() {}
let b = new a();
Object.prototype.toString.call(b); // [object Object]