前端进阶之道
1. 数据类型
JS分两种类型,原始类型和对象类型。
原始类型:
1.boolean
2.number
3.string
4.undefined
5.null
6.symbol
7.bigint
对象类型:
1.Object(Array,RegExp,Math,Map,Set)
2.Function
2. 类型判断
2.1 typeof
原始类型中除了null,都可以用typeof判断。
typeof判断函数为function,其他均为object。
2.2 instanceof
常用于判断对象类型
2.3 Object.prototype.toString
最佳选择,能判断的类型最完整
2.4 isXXX API
isArray(),isNaN()
3. 类型转换
1 | Number(false) // -> 0 |
转布尔值规则:
1.undefined、null、false、NaN、’’、0、-0都转为false
2.其他所有值都转为true,包括所有对象
转数字规则:
1.true为1,false为0
2.null为0,undefined为NaN,symbol报错
3.字符串看内容,如果是数字或者进制值就正常转,否则就NaN
4.对象的规则隐式转换再讲
4. this
4.1 普通函数
谁调用this指向谁
1 | var c = new foo() |
使用apply,call,bind改变this,优先级仅次于new
4.2 箭头函数
箭头函数的this取决于定义时的环境
5. 闭包
定义:加入一个函数能访问外部的变量,那么这个函数它就是一个闭包。
闭包会将访问的变量存放在内部对象[[Scopes]]上,因此可以访问到本该销毁的变量
局部变量才是被存储在栈上,全局变量存在静态区域上,其他都存在堆上。(只针对Chrome)
6. new
new可以构建出一个实例,并绑定上this,执行步骤如下:
1.新生成一个对象
2.对象连接到构造函数原型上,并绑定this
3.执行构造函数代码
4.返回新对象
当构造函数中返回一个对象时,内部创建的新对象会被我们返回的对象所覆盖,所以构造函数一般来说不返回对象。
7. 作用域
作用域有三类:
1.全局作用域
2.函数作用域
3.块级作用域
[[Scopes]],定义时就被确定下来,后续不会改变
8. 原型
原型更重要引出继承,概念:
1.每个对象都有一个_proto_指向一个对象,就是原型
2.每个对象的原型都可以通过constructor访问构造函数,构造函数通过prototype访问原型
3.所有函数都可以通过_proto_找到Function对象
4.所有对象都可以通过_proto_找到Object对象
5.对象直接通过_proto_连接起来为原型链,顶层Object对象的原型为null
9. 继承
继承中的class,本质上还是一个函数。
ES5与6继承的区别:
1.ES6继承的子类需要调用super()才能拿到子类,ES5的话是通过apply这种绑定的方式
2.类声明不会提升,和let这些一致
1 | function Super() {} |
10. 深浅拷贝
10.1 浅拷贝
浅拷贝:第一层引用不同
通过assign和扩展运算符实现浅拷贝
1 | let a = {age:1} |
10.2 深拷贝
深拷贝:所有引用不同
使用JSON.parse(JSON.stringify(object))可以实现,不过存在不少缺陷。
也可以通过递归实现深拷贝:
1 | // 利用 WeakMap 解决循环引用 |
11. Promise
高频考点,涉及API,问到all,race。
then,catch,finally都为微任务。其他代码都是宏任务(同步执行)
这些微任务在Promise状态为非pending时加入队列。
同级then下,前一个then执行完后,后面的才会加入任务队列。
最开始调用的then会首先依次加入任务队列。
同一个promise的每个链式调用的开端会首先依次进入队列。
11.1 async/await
async/await(ES8)
阻塞await后面的内容。
12. 事件循环
异步只是延迟执行同步代码。其他线程不影响(Web worker)。
Task(宏任务):同步代码、setTimeout回调、setInterval回调、IO、UI交互事件、postMessage、MessageChannel。
MicroTask(微任务):Promise的回调,Mutation observer回调,queueMicrotask回调。
执行顺序如下:
1.执行同步代码
2.执行完所有同步代码后且执行栈为空,判断是否有微任务需要执行
3.执行所有微任务且微任务队列为空
4.是否有必要渲染页面
5.执行一个宏任务
13. 模块化
CommonJS,ES6的ESM
14. 垃圾回收
分两个空间,新生代和老生代。
14.1 新生代
使用Scavenge GC算法
也分两个部分,From空间,To空间。
From占满时,启动算法检查存活的对象复制到To空间中,会和To空间互换。
14.2 老生代
使用标记清除和标记压缩算法
经历过Scavenge算法后还存活,To空间对象占比大小超过25%,会将新生代移到老生代。
启动标记清除算法条件:
1.某一个空间没有分块
2.空间中被对象超过一定限制
3.空间不能保证新生代中的对象移动到老生代中
标记活对象,销毁没被标记的对象
15. 其他
0.1+0.2 !== 0.3
浮点数用二进制表示的时候是无穷的,因为精度的问题,两个浮点数相加会造成截断丢失精度,因此再转换为十进制就出了问题。