maiy's blog

明源云面试

2020-07-16

之前在明源云进行了电话面试,面试题大概如下:

Vue

vueRouter history模式与hash模式

hash

hash模式主要是根据window.onhashchange事件函数监听url里hash值的变换来进行路由的跳转,而且服务器永远只会识别/#/前面的部分,不需要在服务器配置所有的路由url

history

history模式没有/#/号,是根据history这个浏览器对象来实现路由的跳转,有gobackforwardpushStatereplaceState等api,通过pushState把页面的状态保存在state对象中,然后根监听window.onpopstate事件函数来获取event.state这个状态进行页面还原。但是由于histroy模式没有/#/这个hash标识,就需要服务器直接所有的路由地址,否则当刷新某个路由地址时,去请求服务器,服务器找不到这个地址就会报404的错误。

Proxy解决了什么问题

  • 解决了object.definePropertiy的无法监听到对象的添加与删除,需要调用Vue.set方法进行添加,this.$delete方法进行删除才能监听到响应式系统,还可以对整个data进行重新赋值
  • 不能监听到数组的变化,现在可以是因为重新数组的一些方法
  • 只能劫持到对象的属性,如果属性是对象还需要进行深度遍历

vue data为何要是function

因为组件复用会共享data,如果data是对象的话,一个组件修改data那同时也会影响到另一个data,现在组件使用了函数就解决这个问题,基于必包。

nextTick

意思就是在下次DOM更新循环结束之后执行回调,比如我需要在更新data后需要获取真实的DOM的value,但此时是没有更新的,我们就可以使用nextTick设置个回调函数即可。


React

React hook的特性

为什么要hook

  • 使函数组件能够拥有状态
  • 很难在组件之间服用状态逻辑(解决复用问题使得很多高阶组件嵌套、render prop导致的嵌套地狱)
  • 复杂组件变得难以理解(hook可以把一些逻辑拆分为状态函数)
  • class难以理解,需要去理解this的工作方式

React高阶组件 与 render propsx

高阶组件

本质是函数,接受组件作为参数,返回一个新的组件。主要是为了解决组件功能复用问题。有两种方式

  • 属性代理:主要是继承React.Component,然后在render方法里引用传进来的组件。
    • 可以操作props
    • 可以ref访问组件实例
    • 操作state
    • 组合html
  • 反向继承:直接继承组件,render里也是返回该组件
    • 操作state
    • 渲染劫持,可以操作render
    • 会丢失原本显示名
  • 高阶组件的缺点
    • 难以溯源,如果是由多个hoc组成的话,需要翻每个hoc知道各自的属性
    • props属性名冲突,某个属性可能被多个hoc重复使用
    • 静态构建,需要在页面构建前生成

Render Props

主要也是用于功能复用,本质就是给组件传入一个props,然后在组件render里引用这个props,有以下优点

  • 数据单向流
  • props不会有命名冲突
  • 可以溯源
  • 动态构建,可以在render里渲染
  • 能完成所有hoc的功能

常用的必包

  • 柯里化
  • react的hook
  • vue的component的data
  • 计数器
  • 避免污染全局环境

React生命周期

  • constructor
  • componentWillMount (pass)
  • static getDerivedStateFromProps
  • render
  • componentDidMount
  • shouldComponentUpdate
  • componentWillUpdate(pass)
  • componentWilReceiveProps(pass)
  • static getSnapshotBeforeUpdate
  • componentDidUpdate
  • componentUnMount

左右定宽,中间自适应

绝对定位

左右两边布局设置绝对定位,中间的布局左右margin,缺点是脱离文档流。

flex

容器设置flex布局,中间布局flex等于1,缺点是无法直接优先加载中间布局,需要做别的处理,兼容性不是十分完美。

双飞翼

经典布局,兼容性好,中间内容优先加载。缺点是脱离文档流,需要清除浮动,中间布局额外DOM。

  • 中间布局需要包裹一层content
  • 左和content都需要设置左浮动,右布局设置右浮动
  • content的width=100%,左边的margin-left=-100%,右边的margin-left=-右布局宽度
  • 中间布局设置左右margin为左右布局宽度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <div class="container">
    <div class="content">
    <div class="main">main<div>
    </div>
    <div>left</div>
    <div>right</div>
    </div>
    .left {
    width: 300px;
    display: inline-block;
    float: left;
    margin-left: -100%;
    }
    .right {
    width: 300px;
    float: right;
    margin-left: -300px;
    }
    .container {
    float: left;
    width: 100%;
    }
    .main {
    margin-left: 300px;
    margin-right: 300px;
    }

圣杯布局

也是经典布局,优点是不需要多余的DOM,其余和双飞翼一样

  • 左和中间都需要设置左浮动,右布局设置右浮动
  • main的width=100%,左边的margin-left=-100%,右边的margin-left=-右布局宽度
  • 左右布局设置为相对布局,left=-300px;右布局right=-300px;
  • 容器设置左右margin为300px
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <div class="container">
    <div class="main">main<div>
    <div>left</div>
    <div>right</div>
    </div>
    .left {
    float: left;
    width: 300px;
    display: inline-block;
    margin-left: -100%;
    position: relative;
    left: -300px;
    }
    .right {
    float: right;
    width: 300px;
    display: inline-block;
    margin-left: -300px;
    position: relative;
    right: -300px;
    }
    .main {
    float: left;
    width: 100%;
    }
    .container {
    margin-left: 300px;
    margin-right: 300px;
    }

useCallback 与 useMemo

这两个hook函数的作用都是基于给定的依赖来进行缓存,而区别在于useCallback返回的是函数,而useMemo返回的是一个值。用法主要是在给子组件传递参数时,可以配合React.memo(作用是会对props做一个浅层比较,props没有修改的话,就不会渲染组件)来对子组件判断是否需要更新,从而节省不必要的更新。

diff的key值

key值可以在DOM中的某些元素被增加或者删除的时候帮助React识别哪些元素发生了变化。

  • key值相同,组件有所变化,react会只更新组件对应变化的属性。
  • key值不同,组件会摧毁之前的组件,讲整个组件重新渲染。

promise的all,race,allSettled

  • all:promiseAll接收一组promise,只有这组promise全部状态变成fulfilled后,promiseAll状态才会变成fulfilled,此时返回值是一个数组,如果任意一个promise变成rejected,则promiseAll状态也会变成rejected,rejected返回值传给promiseAll
  • race:参数与all的是一样,但是race只要任意一个promise状态变更后,promiseRace的状态也会跟着变,比如可以用来给promise设置超时时间。
  • allSettled:只有所有的promise状态都变更后,包装实例才会结束,结束后状态总是fulfiled,参数是数组,如[{status: ‘fulfilled’, value: 43}]。
  • any:只要任意一个变成fulfilled后,实例才会变成fulfilled,等所有实例变成rejected后,实例才会变成rejected。

bfc

bfc是一个独立的容器,有它自己的布局流

触发BFC

  • body 根元素
  • 浮动
  • 绝对定位
  • disaplay: inline-block、table-cells、flex
  • overflow:hidden、auto、scroll

应用

  • 解决BFC下外边距折叠
  • 清除浮动

清除浮动

  • 额外标签,添加标签加上属性clear: both;
  • overflow: hidden,内容被隐藏
  • after伪元素
    1
    2
    3
    4
    5
    .container::after {
    content: '';
    clear: both;
    display: block;
    }

盒子模型

content-box

元素的宽度=width+padding+border+margin

border-box

元素的宽度=width,所有的padding、border、margin都包含在width里了

thunk与sega有啥不同

thunk

  • 使用简单,直接dispatch一个函数
  • action形式不统一
  • action不易维护,每个异步都需要一个函数
  • 操作分散,异步操作dispatch被分散在各个action中

sega

自己封装了一整套异步处理流程

  • 使用了generator语法
  • 集中处理所有异步操作
  • action是普通对象
  • 使用effect可以方便单元测试
  • 异步操作流程可控制,随时取消
  • 学习成本高

什么时候触发gpu加速

可以通过CSS属性

  • translate3d
  • translateZ
  • rotate
  • scale

webpack 懒加载

可以使用类似babel-plugin-syntax-dynamic-import这种预处理器,在使用时才去加载模块代码

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章