- Published on
js基础之类型
js 类型是一个比较常见的考点
原始类型
在 JS 中,存在着 7 种原始类型,分别是:
Boolean
Null
Undefined
Number
String
Symbol
BigInt
原始类型存储的是值,没有函数可以调用。
那么有个问题,为什么语句'1'.toString()
是正确的呢?
这个语句其实做了以下事情:
- 创建 Object 类实例。为什么不是 String ?原因在于其中可能包含 Symbol 和 BigInt。对他们进行 new 调用都会报错。
- 调用实例方法
- 执行完这个方法并且立即销毁这个实例。
let s = new Object('1')
s.toString()
s = null
对象类型
对象类型和原始类型不同的是,原始类型存储的是值,对象类型存储的是地址(指针)。
当你创建了一个对象类型的时候,计算机会在内存中帮我们开辟一个空间来存放值,但是我们需要找到这个空间,这个空间会拥有一个地址(指针)。
正确判断 null
Object.prototype.toString.call(null) // "[object Null]"
typeof vs instanceof
typeof
对于原始类型来说,除了 null
都可以显示正确的类型
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof
对于对象来说,除了函数都会显示 object
,所以说 typeof
并不能准确判断变量到底是什么类型.
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
如果我们想判断一个对象的正确类型,这时候可以考虑使用 instanceof
,因为内部机制是通过原型链来判断的。
const Person = function () {}
const p1 = new Person()
p1 instanceof Person // true
var str = 'hello world'
str instanceof String // false
var str1 = new String('hello world')
str1 instanceof String // true
对于原始类型来说,你想直接通过 instanceof
来判断类型是不行的,当然我们还是有办法让 instanceof
判断原始类型的
class PrimitiveString {
static [Symbol.hasInstance](x) {
return typeof x === 'string'
}
}
console.log('hello world' instanceof PrimitiveString) // true
Object.is 与 === 的区别
具体来说就是 +0,-0以及 NaN,NaN的区别。
function is(x, y) {
if (x === y) {
// 1 / +0 为正无穷,1 / -0 为负无穷
return x !== 0 || y !== 0 || 1 / x === 1 / y
} else {
// 两个都是 NaN 返回 true
return x !== x && y !== y
}
}
类型转换
在 js 中,只有三种类型转换
- 转换为布尔值
- 转换为数字
- 转换为字符串
转Boolean
在条件判断时,除了 undefined
, null
, false
, NaN
, ''
, 0
, -0
,其他所有值都转为 true
,包括所有对象。
对象转原始类型
一般非基础类型进行转换时会先调用 valueOf,如果 valueOf 无法返回基本类型值,就会调用 toString
对象在转换类型的时候,会调用内置的 [[ToPrimitive]]
函数,对于该函数来说,算法逻辑一般来说如下:
- 先检测该对象中是否存在
valueOf
方法,如果有并返回了原始类型,那么就使用该值进行强制类型转换; - 如果
valueOf
没有返回原始类型,那么就使用toString
方法的返回值; - 如果
vauleOf
和toString
两个方法都不返回基本类型值,便会触发一个TypeError
的错误。
也可以重写 Symbol.toPrimitive
,该方法在转原始类型时调用优先级最高。
let a = {
valueOf() {
return 0
},
toString() {
return '1'
},
[Symbol.toPrimitive]() {
return 2
},
}
1 + a // => 3
四则运算符
加法运算符不同于其他几个运算符,它有以下几个特点:
- 运算中其中一方为字符串,那么就会把另一方也转换为字符串。
- 如果一方不是字符串或者数字,那么会将它转换为数字或者字符串
1 + '1' // '11'
true + true // 2
4 + [1, 2, 3] // "41,2,3"
对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字
4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN
比较运算符
如果是对象,就通过
toPrimitive
转换对象如果是字符串,就通过
unicode
字符索引来比较
let a = {
valueOf() {
return 0
},
toString() {
return '1'
},
}
a > -1 // true
== VS ===
对于 ==
来说,如果对比双方的类型不一样的话,就会进行类型转换.
假如我们需要对比 x
和 y
是否相同,就会进行如下判断流程:
- 首先会判断两者类型是否相同。相同的话就是比大小了
- 类型不相同的话,那么就会进行类型转换
- 会先判断是否在对比
null
和undefined
,是的话就会返回true
- 判断两者类型是否为
string
和number
,是的话就会将字符串转换为number
- 判断其中一方是否为
boolean
,是的话就会把boolean
转为number
再进行判断 - 判断其中一方是否为
object
且另一方为string
、number
或者symbol
,是的话就会把object
转为原始类型再进行判断
对于 ===
来说,就是判断两者类型和值是否相同
[] == ![] 为何是 true?
首先看右边,! 符号会将后面的变量强转为 boolean 值,由于 [] 转换为 boolean 是 true,故右边为 false,然后依照上方的第 5 条,将 false 转换为数字 0。
然后看左边,满足第六条的条件,调用 valueOf,由于空数组调用 valueOf 是转化为 0 ,故返回值是 true。
一些面试题
0.1 + 0.2 === 0.3 嘛?为什么?
在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会发生无限循环,然后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度丢失。
所以总结:精度丢失可能出现在进制转换和对阶运算中
JS 整数是怎么表示的?
通过 Number 类型来表示,遵循 IEEE754 标准,通过 64 位来表示一个数字,(1 + 11 + 52)(1 位数符 + 11 位阶码 + 52 位尾数),最大安全数字是 Math.pow(2, 53) - 1。(符号位 + 指数位 + 小数部分有效位)
symbol 有什么用处
可以用来表示一个独一无二的变量防止命名冲突。
可以利用 symbol
不会被常规的方法(除了 Object.getOwnPropertySymbols
外)遍历到,所以可以用来模拟私有变量。
主要用来提供遍历接口,布置了 symbol.iterator
的对象才可以使用 for···of
循环,可以统一处理数据结构。调用之后回返回一个遍历器对象,包含有一个 next 方法,使用 next 方法后有两个返回值 value 和 done 分别表示函数当前执行位置的值和是否遍历完毕。
Symbol.for() 可以在全局访问 symbol。
+ [] 和 [] + 的区别
;[] + {} // "[object Object]"
{
}
;+[] // 0
看第一个,[] 会强转为 "",强转为字符串为 "[object Object]"
。两个字符串相加,得到最终结果。
第二个,编译器会把 当作一个空代码块,可以理解为全局作用域下一个没有用的 符号而已,可以把 {} + []
当作 + []
,而+ []
是强制将[]
转换为number ,转换的过程是 + []
--> +""
-->0
最终的结果就是0。
但是我们执行console.log({}+[])
和console.log([]+{})
,结果是一样的,因为没有一个语句或者表达式的头部。
Symbol 类型转换
- 不能被转换为数字
- 能被转换为布尔值(都是 true)
- 可以被转换成字符串 "Symbol(cool)"
假值列表
- undefined
- null
- false
- +0, -0, NaN
- ""
NAN 以及 typeof NAN
NaN 指的是 Not a Number,表示非数字,typeof NaN = 'number'
如何让if(a == 1 && a == 2)条件成立?
var a = {
value: 0,
valueOf: function () {
this.value++
return this.value
},
}
console.log(a == 1 && a == 2) //true