2019-06 中旬 ✅
- 创建于:2019-06-11
- 更新于:2023-03-16

# 2019-06-20: react 性能优化 ✅✅
好好想想先 😌
- 参考链接
- 一句话
- 利用 shouldComponentUpdate 和 PureComponent 避免过多 render function
- 不要直接改变 setState 数据
- 虚拟化长列表 & 常用库 react-virtualized
- 合理组织 React Component:React Component Patterns
- 在希望发生重新渲染的 DOM 上设置同级唯一 key 以触发重新渲染
- 尽量将 props 和 state 摊平,只传递 component 需要的 props,慎将 component 当作 props 传入
# 2019-06-19: react hooks, 前景 ✅✅
好好想想先 😌
- 参考链接
- 一句话
- 函数式组件的爆发
# 2019-06-18: jsx 语法为什么 需要 import react 包?✅✅
好好想想先 😌
- 参考链接
- 一句话
- 在 Babel 轉譯我們的 App.js 的時候,會把 JSX 語法糖轉換為 React.createElement 方法。
# 2019-06-17: React 的 Fiber 架构,reconciler 阶段和 commit 阶段各做什么?💊✅✅
好好想想先 😌
- 参考链接
- 一句话
- React 16 之前是栈调度器
- Stack reconciler 的工作流程很像函数的调用过程。父组件里调子组件,可以类比为函数的递归(这也是为什么被称为 stack reconciler 的原因)。在 setState 后,react 会立即开始 reconciliation 过程,从父节点(Virtual DOM)开始遍历,以找出不同。将所有的 Virtual DOM 遍历完成后,reconciler 才能给出当前需要修改真实 DOM 的信息,并传递给 renderer,进行渲染,然后屏幕上才会显示此次更新内容。对于特别庞大的 vDOM 树来说,reconciliation 过程会很长(x00ms),在这期间,主线程是被 js 占用的,因此任何交互、布局、渲染都会停止,给用户的感觉就是页面被卡住了。
- Fiber reconciler 允许渲染过程分段完成,而不必须一次性完成,中间可以返回至主进程控制执行其他任务。
- ReactFiber 基于时间分片的限量更新
requetIdleCallback - reconciliation: 简单来说就是找到需要更新的工作,通过 Diff Fiber Tree 找出要做的更新工作,这是一个 js 计算过程,计算结果可以被缓存,计算过程可以被打断,也可以恢复执行
- commit: 提交更新并调用对应渲染模块(react-dom)进行渲染,为了防止页面抖动,该过程是同步且不能被打断
- React 16 之前是栈调度器
# 2019-06-16: React 16 新增的生命周期,为什么要废弃以前的生命周期?✅✅
好好想想先 😌
- 参考链接
- 一句话
- 废弃
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
- 新增
static getDerivedStateFromPropsgetSnapshotBeforeUpdatecomponentDidCatch - react 打算在 17 版本推出新的 Async Rendering,提出一种可被打断的生命周期,而可以被打断的阶段正是实际 dom 挂载之前的虚拟 dom 构建阶段
- 废弃
# 2019-06-15: 函数柯里化有什么作用?✅✅
好好想想先 😌
- 参考链接
- 一句话
- 柯里化,可以理解为提前接收部分参数,延迟执行,不立即输出结果,而是返回一个接受剩余参数的函数
- 优点:参数复用、延迟运行、扁平化
# 2019-06-14: 不用 call 和 apply 如何实现 bind? ✅✅
好好想想先 😌
- 参考链接
- 一句话
- 利用 eval 实现
- 利用中间对象实现
- 代码实现
Function.prototype.myCall = function (context) { // 如果没有传或传的值为空对象 context指向window context = context || window context.fn = this //给context添加一个方法 指向this // 处理参数 去除第一个参数this 其它传入fn函数 let arg = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组 context.fn(...arg) //执行fn delete context.fn //删除方法 }
# 2019-06-13: 什么是原型和原型链,实现继承有哪些方式?✅✅
好好想想先 😌
参考链接
一句话
- 每个实例对象( object )都有一个私有属性(称之为 __proto__ )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( __proto__ ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节
obj.__proto__ === Obj.prototype
代码实现
- 原型链继承
function Parent() { this.name = '张三' } Parent.prototype.getName = function () { console.log(this.name) } function Child() {} Child.prototype = new Parent() var child1 = new Child()- 构造函数继承
function Parent() { this.names = ['张三', '李四'] } function Child() { Parent.call(this) } var child1 = new Child()
# 2019-06-12: instanceof 原理和代码实现? ✅✅
好好想想先 😌
- 参考链接
- 一句话
- js 在底层存储变量的时候,会在变量的机器码的低位 1-3 位存储其类型信息,对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的,由于 null 的所有机器码均为 0,因此直接被当做了对象来看待
obj.__proto__ === Obj.prototype
- 代码实现
function instanof(left, right) { return left.__proto__ === right.prototype }
# 2019-06-11: 深拷贝和浅拷贝有什么不同,代码实现 ✅✅
好好想想先 😌
- 参考链接
- 一句话
深拷贝和浅拷贝的主要区别就是其在内存中的存储类型不同,基本数据类型存放在栈中,基本数据类型值不可变;引用类型存放在堆中,引用类型值可变 - 代码实现
function extend(target, source, deep) { for (key in source) { if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { if (isPlainObject(source[key]) && !isPlainObject(target[key])) { target[key] = {} } if (isArray(source[key]) && !isArray(target[key])) { target[key] = [] } extend(target[key], source[key], deep) } else if (source[key] !== undefined) { target[key] = source[key] } } }