JS 的数据类型
基本数据类型
- 存储在栈中
- 无共享概念,赋值后毫无相关
引用数据类型
-
数据存储在堆中,对象的引用地址存放在栈中
-
存在数据共享,赋值的对象的地址,一个改变另外一个也随之改变
-
作为实参,传入的也是对象的引用地址,改变其引用地址的值,共享改引用地址的变量都会跟着改变
数据类型检测
typeof、instanceof、Object.prototype.toString.call()、constructor
typeof
可以识别基本数据类型,null除外
不可以识别引用类型(Function除外)
instanceof
不可以识别基本数据类型
可以识别内置对象类型【object、Date、Array】,可以识别自定义对象数据类型【通过 new 的构造函数】
Object.prototype
可以识别基本数据类型,内置对象类型
不能识别自定义对象数据类型【通过 new 的构造函数】
constructor
可以识别基本数据类型【undefined和null除外】
可以识别内置对象类型和自定义对象类型
function getconstructorType(obj) {
return obj && obj.constructor && obj.constructor.toString().match(/function\s*([^(]*)/)[1];
}
getconstructorType([])
类型转换
练习
'123' == 123 // false or true?
'' == null // false or true?
'' == 0 // false or true?
[] == 0 // false or true?
[] == '' // false or true?
[] == ![] // false or true?
null == undefined // false or true?
Number(null) // 返回什么?
Number('') // 返回什么?
parseInt(''); // 返回什么?
{}+10 // 返回什么?
let obj = {
[Symbol.toPrimitive]() {
return 200;
},
valueOf() {
return 300;
},
toString() {
return 'Hello';
}
}
console.log(obj + 200);
强制类型转换
toString()、String()、Number()、parseInt()、parseFloat()、Boolean()
Number()
布尔值返回 0或1
数字返回自身
undefined返回 NaN
null 返回 0
symbol返回 NaN
字符串:纯数字字符串
"1.12"
、或者(0X / 0x) 开头的十六进制字符串转成十进制、允许正负号;空字符串转0,其他字符串格式均为NaN如果是对象:如果对象部署了[Symbol.toPrimitive],则调用 此方法;否则调用 valueOf() 方法,然后根据上面的规则转换valueOf返回的值;如果转换的结果是NaN,则调用对象的toString() 根据上面的规则对返回的值进行转换
Boolean()
0、-0、+0、’’, false、null、undefined、NaN,其他的都是true
String()
任何类型转的的都是字符串类型
toString()
null、undefined不支持使用toString()、symbol、boolean支持通过值调用toString,number、object不支持值调用,只支持赋值变量后调用
parseInt
整数返回自身,浮点型整数部分4.12 => 4;
boolean、null、undefined、NaN=> NaN
symbol 报错
字符串:空字符串、非纯数字字符串=> NaN;纯数字字符串支持正负号转换为 正负整数;支持-0X / 0x 开头的十六进制字符串 parseFloat(0x11)
如果是对象则跟Number的转换规则是一样的
parseFloat
数字返回自身
boolean、null、undefined 、NaN => NaN
symbol 转换错误
字符串:空字符串、非纯数字的返回NaN,纯数字字符串返回数字,支持正负号,支持-0X / 0x 开头的十六进制字符串 parseFloat(0x11)
隐式类型转换
逻辑运算符(&&、||、!),运算符(+、-、*、/);关系操作符(>、<、>=,<=、),相等操作符(),条件操作符(if / while),类型不一致都会产生隐式类型转换
==符合隐式类型转换
1、操作符两边类型一致,则不进行隐式类型转换
2、其中一个是 null 或 undefined,另外一个必须是undefined或null,否则false
3、symbol 返回 false
4、string 和number进行对比,将字符串转成数字进行对比
5、如果一个值是 boolean ,那么将会转成number
6、如果一个值是 object,另外一个是 number、string、symbol ,
就会把 object 转成原始类型(这点非常重要)
,通过调用(object.valueOf 或者 object.toString):[] == 0 => “” == 0 => 0 == 0 => true7、!的优先级是大于 ==,会先执行 ![]
null == undefined // true 符合第二点
null == 0 // false 符合第二点
'' == null // false 符合第二点
'' == 0 // true 符合第四点 字符串转隐式转换成Number之后再对比
'123' == 123 // true 符合第四点 字符串转隐式转换成Number之后再对比
0 == false // true 符合第五点 布尔型隐式转换成Number之后再对比
1 == true // true 符合第五点布尔型隐式转换成Number之后再对比
var a = {
value: 0,
valueOf: function() {
this.value++;
return this.value;
}
};
// 注意这里a又可以等于1、2、3
console.log(a == 1 && a == 2 && a ==3); //true 通过第六点隐式转换
// 注:但是执行过3遍之后,再重新执行a==3或之前的数字就是false,因为value已经加上去了,这里需要注意一下
“+” 隐式类型转换
两边都是数字则进行加法运算
其中一个是字符串,另外一个是 null、undefined或boolean值则对值进行toString转成字符串再拼接;如果另外一个是对象、数组、正则等;则根据对象的转换方法进行转成后再拼接(转换优先级 Symbol.toPrimitive 再次是 valueOf 其次是toString() )
其中一个是数字,另一个是 undefined、null、boolean,则会将其转成数字进行加法运算,另一个是对象的话参考上一条
其中一个是字符串另一个是数字则进行拼接
其中一个是字符串,另外一个是bigint,将Bigint转成字符串相加 “1” + 1n => “11”
number不能和BigInt进行相加 :1+1n => err
1 + 2 // 3 常规情况
'1' + '2' // '12' 常规情况
// 下面看一下特殊情况
'1' + undefined // "1undefined" 规则1,undefined转换字符串
'1' + null // "1null" 规则1,null转换字符串
'1' + true // "1true" 规则1,true转换字符串
'1' + 1n // '11' 比较特殊字符串和BigInt相加,BigInt转换为字符串
1 + undefined // NaN 规则2,undefined转换数字相加NaN
1 + null // 1 规则2,null转换为0
1 + true // 2 规则2,true转换为1,二者相加为2
1 + 1n // 错误 不能把BigInt和Number类型直接混合相加
'1' + 3 // '13' 规则3,字符串拼接
Object的转换规则
如果部署 Symbol.toPrimitive 方法,则优先调用再返回,如果返回值不是基础类型,则报错,如果是基础类型就返回不报错
调用 valueOf() ,如果转换为基础类型则返回
调用 toString(),如果转换为基础类型则返回
如果以上都没有返回基础类型,都error
注意:默认会调用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也去掉,则调用toString返回'31'(字符串拼接)
// 再看两个特殊的case:
10 + {}
// "10[object Object]",注意:{}会默认调用valueOf是{},不是基础类型继续转换,调用toString,返回结果"[object Object]",于是和10进行'+'运算,按照字符串拼接规则来,参考'+'的规则C
[1,2,undefined,4,5] + 10
// "1,2,,4,510",注意[1,2,undefined,4,5]会默认先调用valueOf结果还是这个数组,不是基础数据类型继续转换,也还是调用toString,返回"1,2,,4,5",然后再和10进行运算,还是按照字符串拼接规则,参考'+'的第3条规则
题目
{} == ! {} // false
看完object的转换规则:
{} == ! {} ==》
{} == false【!优先级比==高先隐式转成boolean:true取反为false】 =>
{} == Number(0) 【如果是boolan会隐身转成number】 =>
({}).toString() == 0 => 【对象根据转换规范执行转换基础类型】
'[object Object]' == 0 => 【字符串跟数字类型对比会隐式转成number】
Number('[object Object]') == 0 ==> NaN == 0 ==>false //注意不是:[Object Object] == 0 -> false
//验证注释说明
{} == '[object Object]' ==>
({}).toString() == '[object Object]'
'[object Object]' == '[object Object]' => true