js 数据类型
概念:
javaScript的数据类型目前有8种:

- 基础类型存储在栈内存,在引用或拷贝时,会创建一个完全相等的变量;先入后出。
- 引用类型存储在堆内存,存储的是地址,多个引用指向同一个地址,这里会涉及一个“共享”的概念。
-
栈内存中变量一般在它的当前执行环境结束就会被销毁被垃圾回收制回收, 而堆内存中的变量则不会,因为不确定其他的地方是不是还有一些对它的引用。 堆内存中的变量只有在所有对它的引用都结束的时候才会被回收。
image.png
实例
let a = {name:'张三', age: 20}
function change(b){
b.age = 22
b = {
name: '李四',
age: 24
}
return b
}
let c = change(a)
console.log(c.age)
console.log(a.age)
答案:24,22
原因:函数传参的b,传递的是对象在堆中的内存地址值,执行b.age就改变了a.age的值,而b={...给参数b重新赋值,有了新的地址,最后返回给了c
数据类型检测
typeof(不能用来判断null和引用类型除function)
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'
这里null返回了object,这只是 JS 存在的一个悠久 Bug,不代表 null 就是引用数据类型,可直接通过 ‘===null’来判断就好;
引用数据类型除了 function 会判断为 function以外,其余都是 'object',也是无法判断出来的。
instanceof
new 一个对象时,那这个对象就会成为它原型链上的对象,我们可以通过instanceof判断new的对象是否是之前构造函数生成的对象,这样就基本可以判断出这个新对象的数据类型
let Car = function() {}
let benz = new Car()
benz instanceof Car // true
let car = new String('Mercedes Benz')
car instanceof String // true
let str = 'Covid-19'
str instanceof String // false
let num = new Number('2')
num instanceof Number // true
封装一个instanceOf方法
function myInstanceof(target, dataType){
if(typeof target !== 'object' || taget == null) return false
// getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
let proto = Object.getPrototypeOf(dataType)
while(true){
if(proto == null) return false
if(proto == dataType) return true
proto = Object.getPrototypeOf(proto)
}
}
console.log(myInstanceof(new Number(123), Number)); // true
console.log(myInstanceof(123, Number));
两种方法结合,typeof用来判断基础数据类型(null除外),instanceof用来判断引用类型
Object.prototype.toString
toString是Object原型上的一个方法,返回"[object Xxx]"格式的字符串,Xxx即数据类型
Object可以直接调用Object.prototype.toString()返回"[object Object ]"
而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call({}) // 同上结果,加上call也ok
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)
数据类型转换
强制类型转换
Number()、parseInt()、parseFloat()、toString()、String()、Boolean()。parseInt、parseFloat只转换数字,其它都返回NaN
Number() 方法的强制转换规则
- 布尔:false: 0, true: 1
- 数字:自身
- null: 0
- undefined: NaN
- 字符串:
包含数字(或 0X / 0x 开头的十六进制,允许包含正负号)转换为十进制;
包含有效的浮点格式,将其转换为浮点数值;
空字符串,将其转换为 0;
不是以上格式的字符串,均返回 NaN
Boolean()方法的转换规则
- false、0、“” 、undefined、null、NaN:‘false
- 其余:true
隐式类型转换
凡是通过逻辑运算符 (&&、 ||、 !)、运算符 (+、-、*、/)、关系操作符 (>、 <、 <= 、>=)、相等运算符 (==) 或者 if/while 条件的操作,如果遇到两个数据类型不一样的情况,都会出现隐式类型转换
'=='转换规则
- 类型相同,不用转换
- 有一个为null或undefined,另一个必须也是,否则返回false
- 有一个Symbol,返回false
- 一个string、number,转为number再对比
- 如果一个操作值是 boolean,那么转换成 number
- 如果一个操作值为 object 且另一方为 string、number 或者 symbol,就会把 object 转为原始类型再进行判断(调用 object 的 valueOf/toString 方法进行转换)
null == undefined // true 规则2
null == 0 // false 规则2
'' == null // false 规则2
'' == 0 // true 规则4 字符串转隐式转换成Number之后再对比
'123' == 123 // true 规则4 字符串转隐式转换成Number之后再对比
0 == false // true e规则 布尔型隐式转换成Number之后再对比
1 == true // true e规则 布尔型隐式转换成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 f规则 Object隐式转换
Object的转换规则
对象转换的规则,会先调用内置的 [ToPrimitive] 函数,其规则逻辑如下:
- 如果部署了 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也去掉,则调用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条规则
总结
这篇文章是我学习拉勾的若离老师的小课CV的