大家好,我是梅巴哥er
。今天3.30,继续努力
1,问:说说react的生命周期
答:
- 16.4版本React组件的生命周期,分为3个阶段(
标红为常用的生命周期
)- 挂载
- 更新
- 卸载
- 挂载: 当组件实例被创建并插入DOM时,生命周期调用顺序如下
constructor(props)
- 初始化state或绑定方法,在里面配置this.state = {…}
- 如果不初始化state或不绑定方法,则不需要实现构造函数
- static getDerivedStateFromProps(props, state)
- 在调用render方法之前调用,并且在初始挂载及后续更新时,都会被调用。
render()
- render()函数是纯函数,也是class组件中,唯一必须实现的方法
- 当render被调用时,它会检查this.props和this.state的变化,并返回不同的数据类型,根据不同的类型,把不同的节点渲染到页面。
componentDidMount()
- 会在组件挂载后(插入DOM树中)立即调用。
- 定时器、ajax请求获取数据等,应该放在这里。这里是最适合添加订阅的地方。
- 更新: 当组件的this.props或state发生变化时会触发更新
- static getDerivedStateFromProps(props, state)
- shouldComponentUpdate(nextProps, nextState)
- 在执行render之前调用
- 根据shouldComponentUpdate()的返回值,判断React组件的输出是否受当前state或props更改的影响。默认行为是state每次发生变化,组件都会重新渲染。
- 此方法仅作为性能优化的方式而存在
render()
- getSnapshotBeforeUpdate(prevProps, prevState)
- getSnapshotBeforeUpdate在最近一次渲染输出(提交到DOM节点)之前调用。它使得组件能在最近一次发生更改之前从DOM中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值都将作为参数传递给componentDidUpdate()
- 它返回snapshot的值或null
componentDidUpdate(prevProps, prevState, snapshot)
- componentDidUpdate会在更新后立即被调用。首次渲染不会执行此方法
- 卸载: 把DOM从组件中移除时调用
componentWillUnmount()
会在组件卸载及销毁之前直接调用。- 在该方法中执行必要的清理操作,如 清除定时器,取消网络请求,或之前在componentDidMount()中的订阅
2,问:react的Fiber是干什么的?作用是什么?
答:
- 为什么会出现Fiber?
- 在现有react中,更新过程是同步的,这可能会导致性能问题。当react决定加载或更新组件树时,会调用过程中的生命周期,计算和对比虚拟DOM,更新DOM树,整个过程是同步的。也就是说,渲染开始后,在渲染结束前,都不会停止,一路进行到底。这在一般情况下,都没问题。
- 当整个渲染过程中,组件数量过多,就会导致操作时间过长。如果这个时候,用户进行了某种操作,而唯一的主线程在做渲染工作,就没办法停下来对用户的操作做出反应。会出现卡顿现象,这样会影响用户的体验。
- 于是,Fiber就出现了。
- Fiber是一种处理js中同步操作时间过长的react架构
- 它的主要目标是:
- 能够把可中断的任务切片处理
- 能够调整优先级,重置并复用任务
- 能够在父元素与子元素之间交错处理,以支持react中的布局
- 能够在render中返回多个元素
- 更好的支持错误边界
3,问:讲讲宏任务和微任务
4,问:闭包的使用场景
5,问:js事件机制
6,问:手写跨域的各种方法
7,问:说说浏览器的缓存机制
8,问:具体说说XSS和CSRF的攻防
9,问:webpack的配置了解吗?具体说说
10,问:了解http和https吗?了解加密过程吗?
11,问:手写深拷贝
function deepClone(param) {
var obj
if(Object.prototype.toString.call(param) === 'Array') {
obj = []
for(var i = 0; i < param.length; i++) {
obj[i] = deepClone(param[i])
}
} else if(Object.prototype.toString.call(param) === 'Object') {
obj = {}
for(var k in obj) {
obj[k] = deepClone(param[k])
}
}
return param
}
var arr = [1, 2, [3, 4], {a: 1}]
console.log(deepClone(arr))
// [ 1, 2, [ 3, 4 ], { a: 1 } ]
12,问:轮询和websocket的区别
答:
- 轮询:不存在兼容问题,定时发送请求,
- websocket:低版本浏览器可能不能使用,实时获取数据,服务器更新数据后,会实时发送数据给客户端更新。
13,问:js继承有哪些方式,原理和优缺点
答:
- 方法:
- 原型继承
- call继承(经典继承)
- 组合继承(原型+call)
- 寄生继承
- 寄生组合继承
- class类继承(ES6)
- 主要从以下5方面来说区别:
- 是否能在子函数实例上加参数
- 实例是否能调用父函数原型的属性和方法
- 实例调用的引用类型的值是否在所有实例中共享
- 子函数的实例是否也是父函数的实例
- 调用父函数是1次还是2次
14,问:垃圾回收机制
答:
- 引用计数法
- 标记清除法
- 手动清除
15,问:tcp和udp协议
16,问:手写new怎么实现的,中间过程发生了什么
- new的具体步骤:
- 创建一个空对象:
var obj = {}
- 实例对象的原型指向构造函数的原型(创建原型链):
obj.__proto__ = Fn.prototype
- 构造函数的this指向实例(继承构造函数的属性和方法):
var newObj = Fn.apply(obj, args)
- 创建一个空对象:
- 根据这个步骤,来手写new:
// 方式一
function useNew(Fn, ...args) {
// 1,先创建一个空对象
var obj = {}
// 创建原型链
if(Fn.prototype) {
obj.__proto__ = Fn.prototype
}
// 继承构造函数的属性和方法
var newObj = Fn.apply(obj, args)
return newObj instanceof Object ? newObj : obj
}
// 方式二,其实就是用了寄生组合继承的方法
function useNew(Fn, ...args) {
// 在原型上创建一个空对象,把new的第一步和第二步合并了
var obj = Object.create(Fn.prototype)
// 继承Fn的属性和方法
var newObj = Fn.apply(obj, args)
return newObj instanceof Object ? newObj : obj
}
17,问:html渲染过程,重排重绘,以及异步加载css、图片和js,解决阻塞的defer、async等
18,问:margin的百分比是怎么计算的?
19,问:js两种数据类型的区别
- 基本数据类型是引用的值
- 引用数据类型是通过栈里的存储地址,找到对应堆里的值。
20,问:数组的浅拷贝方法有哪些?
21,问:计算机网络分层结构,每层都有哪些协议?
22,问:TCP和UDP的区别
23,问:HTTP缓存机制
24,问:函数柯里化
// 手写一个函数,实现如下计算
add(1, 2) // 3
add(1)(2) // 3
25,问:css哪些属性会导致重排重绘?
26,问:手写三栏布局的多种方法
- 注意:
- 用float方法时,哪个盒子要自适应,就在body里让那个盒子放最后一个。
- 圣杯布局:是container盒子包裹住中间的3个盒子,中间的盒子放最前面,优先加载
- 双飞翼布局:是container盒子只包裹住最中间的1个盒子,中间的盒子放最前面,优先加载
27,问:强缓存和协商缓存,以及相关 的请求响应字段
28,问:怎么获取用户点击链接的次数
// 举个例子
// 需要注意的是,用"javascript:;"来阻止当前页面的刷新
<body>
<a href="javascript:;">点击连接</a>
<h3>0</h3>
<script type="text/javascript">
var a = document.getElementsByTagName('a')[0]
var h3 = document.getElementsByTagName('h3')[0]
var count = 0
a.addEventListener('click', function() {
count++
h3.innerHTML = count
})
</script>
</body>
以上。