到目前为止,javascript有8种数据类型:
/*
1. String
2. Number
3. Boolean
4. Null
5. Undefined
6. Symbol
7. BigInt
8. Object
*/
其中前7种为基本类型,Object 为引用类型。Object 大概分为以下几种:
/*
1. Function 函数对象
2. RegExp 正则对象
3. Date 日期对象
4. Math 数学函数对象
5. Array 数组对象
*/
javascript的数据类型在初始化后会放在不同的内存中,大致分为2种:
- 基础类型存储在栈内存中,被引用和拷贝时,会创建完全相等的变量
- 引用类型会存储在堆内存中,存储的是地址,多个引用会指向同一个地址
let a = 1;
let b = a;
b = 2;
// 此时 a 的值还是 1,b 为 2。因为 a 的值为1是基本类型。把 a 的值赋值给 b 时,适用第一种规则。其它基本类型同理
let objA = {a: 1};
let objB = objA;
objB.a = 2;
// 此时 objA 与 objB 均为 {a: 2}。因为 objA 的值是引用类型。把 objA 的值赋值给 objB 时,适用第二种规则,当 objB 改变时,objA 也会改变
关于javascript的类型检测,大致有三种方式:
- 通过 typeof
- 通过 instanceof
- 通过 Object.prototype.toString.call
typeof 的缺陷只能检测出基本类型(注意:typeof null == 'object' 是javascript历史原因,如需要判断是不是null 类型 直接用 a === null这样的方式 就行),而引用类型除了函数能正确判断其它的只会返回object。
instanceof 则与typeof相反,他无法正确判断基本类型,但可以判断出引用类型。
Object.prototype.toString.call 则能完美的检测出所有类型。
// 例子
Object.prototype.toString.call(1); // [object Number]
Object.prototype.toString.call('1'); // [object String]
Object.prototype.toString.call(new Date()); // [object Date]
javascript中类型转换分为强制类型转换与隐式类型转换,强制类型转换方式包括 Number()、parseInt()、parseFloat()、toString()、String()、Boolean()这几种。
Number()转换规则:
-
如果是boolean,则 true 与 false 转换成 1 和 0
-
如果是数字,返回本身
-
如果是 null,返回0
-
如果是 undefined,返回 NaN
-
如果是字符串:
- 字符串只包含数字(或者0X/0x开头的16进制数字字符串),转换成十进制。
- 字符串为有效的浮点格式,转换成浮点数值。
- 字符串为空串,返回0。
- 其它格式字符串,返回NaN
-
如果是 symbol,抛出错误
-
如果是对象,并且部署了 [Symbol.toPrimitive] ,那么调用此方法,否则调用对象的 valueOf() 方法,然后依据前面的规则转换返回的值;如果转换的结果是 NaN ,则调用对象的 toString() 方法,再次依照前面的顺序转换返回对应的值
Number(true) // 1 Number(1) // 1 Number(null) // 0 Number(undefined) // NaN Number('') // 0 Number('1') // 1 Number('0x11') // 17 Number('0.222') // 0.222 Number('1222a') // NaN let obj = { [Symbol.toPrimitive](hint) { // [Symbol.toPrimitive] 有三种模式 // number,该场合需要转换成数字 // string,该场合需要转换成字符串 // default,该场合即可转换成数字,也可转换成字符串 switch (hint) { case 'number': return 123; case 'string': return 'str'; case 'default': return 'default'; default: throw new Error(); } } Number(obj); // 123 let objA = { valueOf: function() { return 123 } } Number(objA); // 123 let objB = { toString: function() { return 123 } } Number(objB); // 123
Boolean()转换规则:
- 除了 undefined、 null、 false、 ''、 0(包括 +0,-0)、 NaN 转换出来是 false,其他都是 true。即使在对象上布置了[Symbol.toPrimitive] 、valueOf、toString,也会转换成true
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(false) // false
Boolean(NaN) // false
Boolean({}) // true
Boolean([]) // true
let objB = {
toString: function() {
return false
}
}
Boolean(objB) // true
凡是通过逻辑运算符 (&&、 ||、 !)、运算符 (+、-、*、/)、关系操作符 (>、 <、 <= 、>=)、相等运算符 (==) 或者 if/while 条件的操作,如果遇到两个数据类型不一样的情况,都会出现隐式类型转换。
'==' 的隐式类型转换规则
- 如果类型相同,无须进行类型转换;
- 如果其中一个操作值是 null 或者 undefined,那么另一个操作符必须为 null 或者 undefined,才会返回 true,否则都返回 false;
- 如果其中一个是 Symbol 类型,那么返回 false;
- 两个操作值如果为 string 和 number 类型,那么就会将字符串转换为 number;
- 如果一个操作值是 boolean,那么转换成 number;
- 如果一个操作值为 object 且另一方为 string、number 或者 symbol,就会把 object 转为原始类型再进行判断(调用 object 的 valueOf/toString 方法进行转换)。
&&、 ||、 ! 和 if/while 中需要真值时,则调用Boolean()进行转换
// 例子
if ([]) {
console.log('true'); // 能打印出来,[] 转换成boolean值为 true
}
let a = !{}; // false,{} 转换成boolean值为 true 再取反为 false
var b = 1 && []; // 逻辑与运算,两边为真取第二个,否则取第一个假值,1 和 [] 都被转换成boolean值为 true
var b = 1 || []; // 逻辑或运算,两边为假取第二个,否则取第一个真值,1 和 [] 都被转换成boolean值为 true
// 经典题
[] == ![];
/* true。首先因为优先级关系先进行右边的逻辑非运算。右边[]转换成boolean值为 true 再取反为 false。
进行相等判断时,根据规则如果有一方为boolean值,转换成数字在进行判断 [] == ![] --> [] == fasle --> [] == 0。
左边的 [] 转换成数字前会依次调用 [Symbol.toPrimitive] 、valueOf、toString方法直到转换成基本类型。因此
通过toString方法转换成了空字符串"",在转换成数字为 0.则最后为 0 == 0,当然为 true
*/