大家好,我是蛇皮鸡,一名准前端工程师。我对外的输出文章并不会对某个技术进行非常详细的解释,简单的说就是大而泛,旨在了解技术的出现背景、原因和应该如何理解并且优雅的应对面试。只有建立起自己的知识系统,才能装下更多的知识,我希望能先把树干尽量的健壮,再去管叶子是否茂密
数据类型
类型分类
Primitive 原始数据类型
-
空值(表示未定义的值,但是null会被typeof判断为对象属于系统的bug,地址000开头的表示对象,但是空值为 000000xx 全零
- null(意料之内的空值)
- undefined(表示未赋值)
-
基础类型
- string:非常多的接口,String上的各种操作字符串的函数,作为数组或者可迭代对象的各种函数,正则匹配的各种数组(KMP算法)
- number:浮点类型、NaN、-+ / Infinity
- boolean
-
Symbol
- 使用场景:作为对象的键,不重复的属性名、消除开发自定义的不安全字符串常量、各种内置符号(Symbol.iterator、Symbol.toPrimitive、Symbol.hasInstance)
- 用法:
- Symbol() 传入字符串,非字符串被转换为字符串,生成独一无二的值
- Symbol.for() 传入字符串,唯一的不同点就是,相当于单例模式:相同的字符串对应一个独一无二的值。在整个程序内,首次传入新字符串,创建一个Symbol值,再次传入该字符串,返回这个Symbol。Symbol.keyFor(Symbol.for('查询注册信息')) === '查询注册信息'
- Symbol不允许隐式类型转换成 字符串/数字,Number强制转换会报错,String可以,Object的Symbol属性名无法被stringify序列化,也无法被for in遍历(即使通过getOwnPropertyDescriptor获取到为可枚举特性)
-
bigint:大整数,专门为超出JS浮点数范围二无法表示的数设计的
- 使用场景:high-resolution timestamps、large interger IDs
- 表示:整数+n、new Bigint
- 使用:同为Bigint才能使用计算运算符操作,Bigint在相等判断下等同于同数值的Number类型
对象类型(引用)Object
- 基本类型的包装对象:String、Number、Boolean
- Array、Date、RegExp
- 宿主环境,比如Web:Window、Location、
- Map、Set、Weakxxx系列
- Math工具函数:ceil(向上)、floor(向下)、round(四舍五入)、abs(绝对值)、pow/qurt、random(随机函数)
- JSON
- JSON.stringify、parse 转换JSON字符串、解析JSON字符串
- toJSON 为对象提供 stringify 的序列化方法
- JSON.stringify 第二个参数是数组的时候,如果输出的对象JSON会根据数组元素作为属性名进行筛选,转换成希望的“干净的”JSON(特别是在后端处理数据之后)
- Promise
- Error
- EvalError、SyntaxError
- RangeError:一些需要Number数值的内置函数传参的时候,如果数字不在范围内,throw该错误类型
- ReferenceError:未声明的变量被使用(除非是 typeof)、ES6 const、let 块级作用域不能在声明前使用(临时死区)
- TypeError:空值以对象访问属性、内置对象期望的类型和实参不同
数据类型转换
难理解的点其实在于"隐式转换",但核心的一点掌握:解释器会根据你的声明式代码猜测你想要的类型,为 当前的操作符 转换 出合适的操作数类型。
- 三大基本类型转换:
- 遇到 + 号,优先考虑字符串加法、否则能转数字就转数字(非数字的两个操作数,在非+运算前,都是先转换数字再运算)、
- null 转数值为 0,undefined 转数值为 NaN
- null == undefined 为 true(特殊)、null === undefined 为 false
- 对象转换为三大基本类型:
- @@Symbol.toPrimitive
- 如果上面未得到Primitive值,考虑当前操作符需要什么样的类型,优先调用[valueOf, toString]中的一个函数,如果还未得到,再调用另外一个函数
- 都未得到最后返回NaN
判断类型
主要使用五个方面:
- typeof(Function 特殊、null Bug,无法分辨引用类型,只对原始类型利好)
- instanceof 可以被强制修改原型、hasInstance修改判断规则
- Object.prototype.toString(对原始类型没啥用,对引用类型好用)
- 能力检测(比如数组的一些特有方法)
- 标准的检测方法(比如Array.isArray())
进制转换
默认是10进制转换,因此没有感知
- parseInt(variate, radix) 解析一个字符串并返回指定基数的十进制整数, radix 是2-36之间的整数,表示被解析字符串的基数
- 36 >= radix >= 2 ,不然返回NaN
- 第一个非空格字符不能转换为数字,不然返回NaN
- toString(variate, radix) 将variate看出10进制的数,转换为radix为基数的数
他们的功能刚好相反:
parseInt识别variate以radix为基,转换为10进制
toString识别variate以10为基,转换为radix进制
let variate = '34'
variate = parseInt(variate, 5)
variate = variate.toString(5)
//'34'
为什么0.1 + 0.2 === 0.3为false
计算机二进制的表示方法,小数的二进制也是通过0、1表示,只不过小数的权,每次需要除以2,1 => 1、0.1 => 0.5、0.01 => 0.25、0.001 => 0.125。只有0、1,因此0.1是无法完整表示的,只能逼近
那为什么 0.1 === 0.1,因为0.1的逼近规则是底层规定的,同样的数值有同样的逼近规则,比如JavaScript采用 64 位双精度浮点数表示