数据类型-类型转换
基本类型
JavaScript的内存分为栈内存(stack:先进后出)和堆内存(heap:无序存储,根据引用来取)
栈内存:是一种特殊的线性表,它具有后进先出的特性,存放基本类型。 堆内存:存放引用类型(在栈内存中存一个基本类型值保存对象在堆内存中的地址,用于引用这个对象)
基本数据类型-存储在栈
- string: 存储在堆, 地址在栈
- number:NaN 表示非数值(Not a Number),它是一个特殊的数值,用于表示无法表示为数字的值,可以赋值给 number 类型的变量来表示空值,但它的值不等于任何数,包括它本身。因此,在进行 NaN 和其他值的比较时,结果总是返回 false。
- boolean
- null: 表示一个被明确赋值为“空值”的对象
- undefined:表示一个声明了但未被明确赋值的变量,或者访问对象属性时不存在的属性
- symbol:每一个symbol值都是一个全局唯一的字符串,你永远不会知道它里面存的什么,symbol值可以作为对象的属性的键
- bigInt
区别:
- 基本数据类型——按值操作
- 引用数据类型——操作的是堆内存的地址(按引用地址操作)
引用数据类型-存储在堆, 地址在栈
- Object引用类型
- Function
- Array
- Set
- Map
- Set(Set,与Map类似,也是一组key的集合,但是没有value,类似于数组,并且不能存储重复的key)
注意:字符串并没有存到栈中,而是存到了一个别的地方,再把这个地方的地址存到了栈中。(任何语言的string都不可能存在栈上,存在栈上的只是一个指针而已。string内部是个变长的字符数组,不可能给你存在栈上,只有固定大小的对象和值才能在栈上分配空间。)
浏览器执行JS代码
- 从电脑内存中分配出一块内存,用来执行代码(栈内存——>stack)
- 分配一个主线程用来自上而下执行JS代码
复杂值的存储:
- 第一步——内存中分配出一块新内存,存引用类型值(堆–heap)==>内存有一个16进制地址
- 第二步——对象中的键值对依次存储到堆内存里
- 第三步——把堆内存地址和变量关联起来
typeof 操作符返回规则
console.log('1:',typeof null) // 'object'
console.log('2:',typeof undefined) // 'undefined'
console.log('3:',typeof 123) // 'number'
console.log('4:',typeof "abc") // 'string'
console.log('5:',typeof true) // 'boolean'
console.log('6:',typeof Symbol("id")) // 'symbol'
console.log('object:',typeof {}) // 'object'
console.log('function:',typeof function() {}) // 'function' 只有function对象不同结果是function
console.log('Array:',typeof []) // 'object'
const map = new Map([[200, '请求返回成功']])
console.log('map:',typeof map) // 'object'
console.log('set:',typeof new Set([1])) // 'object'
typeof与instanceof
typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断
两种方法都有弊端,并不能满足所有场景的需求,如果需要通用检测数据类型,可以采用Object.prototype.toString
类型比较: ==(隐式转换) 和 ===
总结: == 就是先比较数据类型是否一样。=== 类型不同直接就是 false。
在JavaScript,当运算符在运算的时候,如果两边数据类型不统一,就无法直接计算,编译器会对运算符两边的数据做一个数据类型转换,转成相同的数据类型再计算。
转换规则
- 任意值与布尔值比较,都会将两边的值转化为Number。
console.log('pack' == true); // false
/*
1.布尔值会被toNumber方法转成数-->pack == 1
2.用toNumber转换字符串值。因为字符串包含字母,所以会被转成NaN:就变成了NaN == 1 --->false
*/
如果一个操作值为字符串,另一个操作值为数值,则通过Number()函数将字符串转换为数值
如果一个操作值是对象,另一个不是,则调用对象的valueOf()方法,得到的结果按照前面的规则进行比较 strObj.valueOf() 返回值:表示给定String对象的原始值 说明:valueOf()方法返回一个String对象的原始值,该值等同于String.prototype.toString()----->该方法通常在JavaScript内部被调用,而不是在代码里显示调用。
null与undefined是相等的
console.log(null==undefined) // true
null,undefined 与任何非自身的值对比结果都是false,但是是一个特例。
- 如果一个操作值为NaN,则相等比较返回false
- 如果两个操作值都是对象,则比较它们是不是指向同一个对象
规则6:如果两个操作值都是对象,则比较它们是不是指向同一个对象
console.log([] == []) // false
console.log([] === []) // false
console.log(![]) // false
console.log(![]===false) // true
console.log([] == ![]) // true
1.根据运算符优先级 ,! 的优先级是大于 == 的,所以先会执行 ![],!可将变量转换成boolean类型,null、undefined、NaN以及空字符串('')取反都为true,其余都为false。 [] == ! [] 相当于 [] == false
2.根据上面提到的规则(如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1),则需要把 false 转成 0
也就是 [] == ! [] 相当于 [] == false 相当于 [] == 0
3.根据上面提到的规则(如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较,如果对象没有valueOf()方法,则调用 toString())
4.根据上面提到的规则(如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值)
Number('') -> 返回的是 0
相当于 0 == 0 自然就返回 true了
扩展:空数组/任何对象是true
// 步骤1:初始化后,即使数组arr中没有元素,也是一个object。 typeof arr; "object"
// 步骤2:object,用于判断条件时就会被转化为true。
if([]){
console.log('能进入判断')
}
if(arr){
console.log("it's true")
}
重点扩展:如果将arr与布尔值比较情况就不一样了
console.log([] == false) // true
console.log([] == true) // false
console.log([1] == true) // true
console.log([] == ![]) // true
console.log(!{}) // false
console.log({} == !{}) // false
console.log({} == {}) // false
console.log({} == NaN) // false
/* 果一个操作值是对象,另一个不是,则调用对象的valueOf()方法,得到的结果按照前面的规则进行比较
// 先调用valueOf方法进行转换
{}.valueOf()
//发现valueOf转化完后,依然不时原始值类型,那继续用toString方法转换
{}.toString()//[object object]
//使用Number转换
Number({}.toString())//NaN:NaN是number类型
*/
任意值与布尔值比较,都会将两边的值转化为Number。
如arr与false比较,false转化为0,而arr为空数组,也转化为0。
Number(false)
// 0
Number(arr)
// 0
所以,当空数组作为判断条件时,相当于true。当空数组与布尔值直接比较时,相当于false。
也就出现了以下令人绕圈的现象:
[] == ![];
// true
console.log(`[] !== []`,[] !== []) // true
console.log(`NaN != NaN`,NaN != NaN) // true
console.log(`null == undefined`,null == undefined) // true
console.log(`1 == true`,1 == true) // true
console.log(`null > 0`,null > 0) // false
console.log(`true + 1`,true + 1) // 2
console.log(`undefined + 1`,undefined + 1) // NaN
console.log(`{} + 1`,{} + 1) // [object Object]1
console.log(`[] + {}`,[] + {}) // [object Object]
console.log('分割线===》')
console.log(`'' == '0'`,'' == '0') // false
console.log(`0 == ''`,0 == '') // true
console.log(`0 == '0'`,0 == '0') // true
console.log(`false == 'false'`,false == 'false') // false
console.log(`false == '0'`,false == '0') // true
console.log(`false == undefined`,false == undefined) // false
console.log(`false == undefined`,false == null) // false
console.log(`null == undefined`,null == undefined) // true
/*
number和boolean用==比较时会把boolean转换为number再比较值,true转换为number是1
*/
console.log('分割线===》')
console.log(`!2`,!2) //false
console.log(`!!2==true`,!!2==true) // true
console.log(`[]==true`,[]==true) //false,因为://Boolean([].toString());为false ,[].toString()为空。
console.log(`{}==true`,{}==true) //false
Boolean() 规则
- 使用Boolean(value)方法可以强制转换任意值为boolean类型,除了以下六个值,其他都是自动转为true:
undefined
null
-0
+0
NaN
""(空字符串)
- number类型除了0对应false外,其他都对应true
- 所有对象的布尔值都是true,甚至连false对应的布尔对象也是true。 请注意,空对象{}和空数组[]也会被转成true。
Boolean(new Boolean(false))// Boolean对象会转成true
Boolean([]) // 空数组会转成true
Boolean({}) // 空对象会转成true