js的数据类型
前言
作为JavaScript
的入门级知识点JS
数据类型在整个JavaScript
的学习过程中其实尤为重要
数据类型概念
数据类型大致分为两类来进行存储
- 基础类型存储在栈内存中。被引用或拷贝时,会创建一个完全相等的变量。基础数据类型有
undefined
、null
、Boolean
、String
、Number
、Symbol
、BigInt
- 引用类型存储在堆内存中。存储的是地址,多个引用指向同一个地址,这里会涉及一个“共享”的概念。引用数据类型有
Array
、RegExp
、Date
、Math
、Function
下面用几个例子助于理解
let a={
name:'xlz',
age:18
}
let b=a;
console.log(a.name);//第一个console 输出xlz
b.name='son';
console.log(a.name);//第二个console 输出son
console.log(b.name);//第三个console 输出son
复制代码
这里第一个输出xlz
大家应该都可以理解,那么第二个第三个输出son
原因就是a
是一个对象存储在堆内存。a
变量存储的是堆内存的地址,b=a
是把a
的内存地址引用过来,a
与b
共享一个地址,所以b.name='son'
修改的是这个地址的对象name
属性因此输出都是son
数据类型检测
第一种判断方法:typeof 运算符返回一个字符串,表示操作数的类型。
typeof 1//number
typeof '1'//string
typeof undefined//undefined
typeof true//boolean
typeof Symbol()//symbol
typeof null//Object
typeof []//object
typeof {}//object
typeof console//object
typeof console.log//function
复制代码
typeof 只能检测基本数据类型 引用类型只能检测一个function其余的都是object
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null
代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null
也因此返回 "object"
。
第二种判断方法:instanceof
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
let Car=function(){}
let benz=new Car();
benz instanceof Car//true
let car=new String('Mercedes Benz')
car instanceof String//true
let str='Covid'
str instanceof String//false
复制代码
instanceof
实现原理如下
function myInstanceof(left,right){
//这里先用typeof来判断基本数据类型,如果是,直接返回false
if(typeof left!=='object'||left===null)return false
//getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
let proto=Object.getProtypeOf(left);
//循环往下寻找,直到找到相同的原型对象
while(true){
if(proto===null)return false
//找到相同原型对象,返回true
if(proto===right.prototype)return true;
proto=Object.getProtypeOf(proto)
}
}
复制代码
可以再控制台验证一下是否ok
两种数据类型的差异
-
instanceof
可以准确的判断复杂引用类型,但是不能正确判断基本数据类型。 -
typeof
也存在弊端,它虽然可以判断基本数据类型(null除外)但是引用数据类型中,除了function类型以外,其他的也无法判断
第三种判断方法:Object.prototype.toString
Object.prototype.toString({})//'[object Object]'
Object.prototype.toString.call({})//同上结果'[object Object]'
Object.prototype.toString.call(1)//'[object Number]'
Object.prototype.toString.call('1')//'[object String]'
Object.prototype.toString.call(true)//'[object Boolean]'
Object.prototype.toString.call(function(){})//'[object Function]'
Object.prototype.toString.call(null)//'[object Null]'
Object.prototype.toString.call(undefined)//'[object Undefined]'
Object.prototype.toString.call(/123/g)//'[object RegExp]'
Object.prototype.toString.call(new Date())//'[object Date]'
Object.prototype.toString.call([])//'[object Array]'
Object.prototype.toString.call(document)//'[object HTMLDocument]'
Object.prototype.toString.call(window)//'[object Window]'
复制代码
这种方法可以检测基本数据类型以及引用类型甚至还可以区分window、document
但是要注意的是Object.prototype.toString
返回的是[object Xxx]
类型第一个首字母是大写开头的
结合以上所学实现一个全局类型检测类型的方法
function getType(obj){
let type=typeof obj;
//先进行typeof判断,如果是基础数据类型,直接返回
if(type!=='object'){
return type
}
//对于typeof返回结果是object,在进行如下的判断,正则返回结果
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/,'$1')
}
//代码验证
getType([])//Array toString返回
getType('123')//string typeof返回
getType(window)//Window toString返回
getType(null)//Null toString返回
getType(undefined)//undefined typeof返回
getType(function(){})//function typeof返回
getType(/123/g)//RegExp toString返回
复制代码
数据类型转换
强制类型转换有Number()、parseInt()、parseFloat()、toString()、String()、Boolean()
Number()方法的强制转换规则:
- 布尔值 true和false 分别被转换为1和0
- 数字 返回自身
- null 返回0
- undefined 返回NaN
- 字符串:如果字符串只包含数字,则将其转换为十进制、如果字符串中包含有效的浮点格式,将其转换为浮点数值、如果是空字符串转换为0、如果不是以上格式字符串,均返回NaN
- SYmbol 抛出错误
- 对象,并且部署了[Symbol.toPrimitive] 那么调用此方法,否则调用对象的valueOf()方法
Number(true)//1
Number(false)//0
Number('0111')//111
Number(null)//0
Number('')//0
Number('1a')//NaN
Number(-0X11)//-17
Number(0X11)//17
复制代码
Boolean()方法的转换规则: 除了undefined、null、false、’‘、0、(包括+0,-0)、NaN转换出来是false其余都是true
parseInt()、parseFloat()、toString()、String()可以参照上面的方式自打印结果总结一下
在开发中头疼的不是强制类型转换而是隐式类型转换,隐式类型转换包括:
- 逻辑运算符
&& || !
- 运算符
+ - * /
- 关系操作符
> < <= >=
- 相等运算符
==
-
if/while
条件
这次分析开发中比较常用的==与+的隐式规则
==隐式类型转换规则
- 如果类型相通无需进行转换
- 如果其中一个操作符是
null
或者是undefined
那么另一个操作符必须为null或undefined才会返回true,否则都是false。 - 如果其中一个是Symbol类型那么返回false
- 两个操作符如果都为
String
和Number
类型那么就会将字符串转换为number - 如果一个操作符是
boolean
那么转换成number
- 如果一个操作符值为
Object
且另一方为string、number
或者symbol
就会把object
转为原始类型在进行判断
null==undefined//true 规则2
null==0 //false 规则2
''==null //false 规则2
''==0 //true 规则4 字符串隐式转换numbe在对比
'123'==123 //true 规则4 字符串隐式转换numbe在对比
0==false //true规则5
1==true//true规则5
var a={
value:0,
valueOf:function(){
this.value++;
return this.value
}
}
console.log(a==1&&a==2&&a==3);//true 规则6 object隐式转换
//之前的面试题如果让 a==1&&a==2&&a==3 等式成立
//执行a==1会调用valueOf一次value++一次a==2也是调用valueOf value++一次
//执行过3遍之后,再重新执行a==3或者之前的数字就是false
复制代码
'+'的隐式类型转换规则
- '+'号操作符,不仅可以用作数字相加,还可以用字符串拼接 如果两个都是数字就进行加法运算、如果两个有一个是字符串那么就会是字符串拼接
- 如果其中有一个是字符串,另一个是undefined、null或布尔型则调用toStriing()方法进行字符串拼接。如果是纯对象、数组、正则等,则默认调用对象的转换方法会存在优先级,然后再进行拼接。
- 如果其中有一个是数字,另一个是undefined、null、布尔型和数字,则会转换成数字进行加法运算,对象的情况还是参考上一条规则
1+2 //3 常规情况
'1'+'2' //'12' 常规情况
//特殊情况
'1'+undefined //‘1undefined’ 规则2 undefined转换字符串
'1'+null //‘1null’ 规则2 null转换字符串
'1'+true //‘1true’ 规则2 true转换字符串
'1'+1n //‘11’ 比较特殊字符串和BigInt,BigInt转换为字符串
1+undefined //NaN 规则3 undefined转换数字相加NaN
1+null //‘1’ 规则3 null转换0
1+true //‘2’ 规则1 true转换1
1+1n //错误 不能把BigInt和Number类型混合相加
‘1’+3 // '13'规则1 字符串拼接
复制代码
object的转换规则
- 如果部署了Symbol.toPrimitive方法优先调用再返回
- 调用valueOf,如果转换为基础类型则返回
- 调用toString(),如果转换为基础类型则返回
- 如果都没有返回基础类型会报错
var obj={
value:1,
valueOf(){
return 2
},
toString(){
return '3'
},
[Symbol.toPrimitive](){
return 4
}
}
console.log(obj+1)//输出5
//因为有Symbol.toPrimitive,就优先执行这个;如果Symbol.toPrimitive这段代码删掉,则执行valueOf打印为3,如果valueOf也去掉,则调用toStrig返回‘31’(字符串拼接)
复制代码
本文使用 文章同步助手 同步