这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战」
前言
之前都是忙于业务开发,对前端的基本知识都是用到什么查什么,很少有时间沉下心来自己归纳,总结下基础,有时候,用到什么,觉得值得留意一下的东西,也都是自己笔记里记录下,也不怎么及时整理,然后随着时间的推移,陆陆续续记录的东西都是乱七八糟的,都没整理过,这次,写这个前端的基础系列,整理一下
打算以轻松,闲谈的调调来聊聊,文笔不好,大家将就的看
快速回顾
上文讲了 JS中的内置类型,基本类型 和对象
- 基本类型 又叫原始类型
- 对象类型 又叫引用类型
- 原始类型存储的是值,对象类型存储的是地址(指针)
typeof , instanceof
这2个家伙,在实际业务开发中,用的频率不高,但是讲JS基础,还是要拎出来讲讲的
MDN 中对 typeof 的解释如下
typeof
操作符返回一个字符串,表示未经计算的操作数的类型。
typeof 是否能正确判断类型? 本来以为可以检测出所有的类型,后来实操中发现并不是
typeof
对于原始类型来说,除了 null
都可以显示正确的类型
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
另类
typeof(null) // 'object'
复制代码
typeof
对于对象来说,除了函数都会显示 object
,所以说 typeof
并不能准确判断变量到底是什么类型
typeof(toString) // 'function'
typeof console.log // 'function'
typeof [] // 'object'
typeof {} // 'object'
复制代码
如果我们想判断一个对象的正确类型, typeof 就有些 不来事了

这时候可以考虑使用 instanceof
,因为内部机制是通过原型链来判断的。
MDN 中对 typeof 的解释如下
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
关于原型链,我自己的理解是,把原型链比作是一个基类,而 instanceof
就像这个基类的一个判断类型的方法,通过定义对象的方法,得到一个对象,这个对象的类型就可以用 它的方法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
来判断类型是不行的
那咋搞? 还是有办法让 instanceof
判断原始类型的
class PrimitiveString {
static [Symbol.hasInstance](x) {
return typeof x === 'string'
}
}
console.log('hello world' instanceof PrimitiveString) // true
复制代码
解释下: 你可能不知道 Symbol.hasInstance
是什么东西,其实就是一个能让我们自定义 instanceof
行为的东西,以上代码等同于 typeof 'hello world' === 'string'
,所以结果自然是 true
了。这其实也侧面反映了一个问题, instanceof
也不是百分之百可信的。
常态下 基本 typeof 和 instanceof 一梭子开干即可,但是要扫下基础,那就还是过一遍吧
类型转换
在 JS 中类型转换只有三种情况,分别是:
- 转换为布尔值
- 转换为数字
- 转换为字符串
转Boolean
在条件判断时,除了 undefined
, null
, false
, NaN
, ''
, 0
, -0
,其他所有值都转为 true
,包括所有对象。
对象转原始类型
对象在转换类型的时候,会调用内置的 [[ToPrimitive]]
函数,对于该函数来说,算法逻辑一般来说如下:
- 如果已经是原始类型了,那就不需要转换了
- 如果需要转字符串类型就调用
x.toString()
,转换为基础类型的话就返回转换的值。不是字符串类型的话就先调用valueOf
,结果不是基础类型的话再调用toString
- 调用
x.valueOf()
,如果转换为基础类型,就返回转换的值 - 如果都没有返回原始类型,就会报错
当然你也可以重写 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"
复制代码
如果你对于答案有疑问的话,请看解析:
- 对于第一行代码来说,触发特点一,所以将数字
1
转换为字符串,得到结果'11'
- 对于第二行代码来说,触发特点二,所以将
true
转为数字1
- 对于第三行代码来说,触发特点二,所以将数组通过
toString
转为字符串1,2,3
,得到结果41,2,3
在JS中,true就是1,false 就是 0, 所以
另外对于加法还需要注意这个表达式 'a' + + 'b'
,这个平时不太常见,也讲一下 因为 + 'b'
等于 NaN
,所以结果为 "aNaN"
,别问为什么是这样,因为控制台打印出来就是这样
你可能也会在一些代码中看到过 + '1'
的形式来快速获取 number
类型。你可能也会在一些代码中看到过 + '1'
的形式来快速获取 number
类型。
那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字(这个我熟,这个我经常在代码中使用,有时候我就用 * 代替 parseInt方法来做
)
4 * '3' // 12
4 * [] // 0
4 * [22, 33] // NaN
复制代码
比较运算符
- 如果是对象,就通过
toPrimitive
转换对象 - 如果是字符串,就通过
unicode
字符索引来比较
let a = {
valueOf() {
return 0
},
toString() {
return '1'
}
}
a > -1 // true
复制代码
在以上代码中,因为 a
是对象,所以会通过 valueOf
转换为原始类型再比较值。
总结
- typeof 和 instanceof
- 类型转换
ps: 干巴巴的文字讲了还是比较枯燥,并且难以印象深刻的,大家还是日常使用中,多多体会