当前位置: 首页 > Web前端 > HTML

从一道面试题延伸到N道面试题

时间:2023-03-28 16:04:26 HTML

昨天简单分享了setState的原理,里面讲了setState是同步的还是异步的?这不,勾起了旧日回忆,翻开笔记,想起有一次不错的面试经历。面试官从一道面试题开始,一步步进行,引出各个知识点。这些知识点可以检测面试官的React知识。积分、ES6知识点、JS基础等。在此基础上,结合自己的理解,组织了一个个人认为比较充分的采访,来分享一下双方的客套话。面试正式开始,面试官出一道面试题。下面的代码,A类的值是什么extendsReact.Component{constructor(props){super(props)this.state={a:0}}componentDidMount(){this.setState({a:1});setTimeout(()=>{this.setState({a:2});},0);newPromise((resolve)=>{resolve(this.setState({a:3}));}).then(()=>{this.setState({a:4});});}render(){console.log("state",this.state.a);返回

{this.state.a}
;}}本题考察“React渲染生命周期”和“setState是同步还是异步”知识点答案是:0,3,4,2首先是React渲染生命周期,挂载时,其生命周期调用顺序为:constructorstaticgetDerivedStateFromProps()rendercomponentDidMountso先渲染state.a,值为0,然后进入componentDidMount生命周期,this.setState({a:1})和this.setState({a:3})是同步操作,并且setTimeout会设置回调函数(即()=>{this.setState({a:2})})到宏任务中,然后回调函数(即()=>{this.setState({a:4})})将被放置在微任务中,因为(lega在cy模式下)setState同一时期的setState会被批处理合成一个setState,后者为主,所以this.setState({a:1})会被覆盖,因为调用了setState并且触发了一次update,也就是再次Render,此时的state.a显示为3。调用完macrotask后,查看microtask队列,发现有未执行的回调函数。执行this.setState({a:4})并再次调用setState触发更新。State.a显示4。microtask队列为空后,查看macrotask队列,发现回调函数this.setState({a:2})执行并触发更新。state.a显示2,所以结果是:0,0,4,2不知道对不对~~我们把这道题转化成classAextendsReact.Component{constructor(props){super(props)this.state={a:0}}componentDidMount(){this.setState({a:1});console.log("a",this.state.a);setTimeout(()=>{this.setState({a:2});console.log("a",this.state.a);},0);newPromise((resolve)=>{resolve(this.setState({a:3}));console.log("a",this.state.a);}).then(()=>{this.setState({a:4});console.log("a",this.state.a);});}render(){return
{this.state.a}
;}}不是在render中显示state.a,而是在调用setState后检查state.a的值,会发生什么?适配题主要考察组件数据更新和视图更新是两个不同的东西。答案是:0、0、3、2首先都在componentDidMount中,其次和前面的情况一样,调用顺序是this.setState({a:1});this.setState({a:3});this.setState({a:4});this.setState({a2});不同的是,调用this.setState({a:1})和this.setState({a:3})后,数据不会立即更新,调用setState后,调用会被推入队列,以在最后一起执行(批处理),所以此时如果看state.a的值,会发现还是0,因为还没有触发批处理和Promise等原生事件setTimeout会同步执行,值会显示为WhatdoyousetState,我给你看。我们在上面两个例子中谈到了EventLoop。在React中,为了性能优化,会处理setState。如果是在浏览器环境下,上面的例子会如何显示呢?console.log('0')setTimeout(()=>{console.log("1");},0);newPromise((resolve)=>{resolve()console.log("2");}).then(()=>{console.log("3");});console.log('4')这道题主要考浏览器的EventLoop机制答案:0,2,4,3,1第一个值为0,毫无疑问遇到setTimeout,所以console.log("1")进入宏任务队列,因为newPromise中的执行函数会同步执行,而"console.log("3inthen")"会进入微任务,所以第二个值为2,然后是第三个value为4,又因为EventLoop机制(macrotask-执行所有microtasks-然后到macrotask队列的第一个),所以先执行microtask,第四个value为3,最后执行macrotask(setTimeout),而第五个值是5。既然说到Promise,我们不妨测试一下Promise。手写一个太麻烦了,没必要去考教材。然后说说为什么.then可以用在promise中,它的链式调用原理是什么?在每次newPromise()之后,可以是.then().then().then(),因为每次调用then后都会返回一个Promise实例,所以可以一直调用。这样,链式调用的核心就是调用方法后返回对象本身(returnthis),那么我们有一个问题,题目是classOperator{...}varop=newOperator(1)op.add(3).minus(2).multi(2).divide(1)在运算符构造函数中写出加、减、多、除。我的答案是:classOperator{constructor(initNum){this.num=initNum;}add(value){this.num=this.num+valuereturnthis}minus(value){this.num=this.num-value;returnthis}multi(value){this.num=this.num*value;归还这个;}divide(value){this.num=this.num/value;归还这个;}}从这道题中,我们可以得出类,ES6特性,柯里化等等。总结和扩展了一道this.setState的面试题的各种题,即考察了面试官对this.setState的理解,考察了浏览器的EventLoop,并且扩展了Promise的链式调用,用一道题来考察面试官的JS基础能力。之后还可以问ES6特性和Currying,知识广度变大,可以更好的考面试官