记录一些面试题

169 阅读11分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

一、grid的使用

1、gridflex的比较

grid 可以看作是二维的布局flex一维的布局

2、grid的属性

  1. grid-template-columnsgrid-template-rows: 定义行列的宽度,宽高的设置可使用px/%/repeat()/auto-fill关键字/fr关键字/minmax()函数/auto关键字,使用案例有:
// 表示每列宽度100px,每行有3div{
    display: grid;
    grid-template-columns: 100px 100px 100px;
}
// 表示每行有4列,列宽度为20% 30% 20% 30%
div{
    display: grid;
    grid-template-columns: repeat(2, 20% 30%);
}
// 表示列宽100px,每行自动填充,填充不下换行
div{
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px); 
}
// 表示每行自动填充,填充不下换行,列宽度为100px 100px 200px …………
div{
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px, 1fr, 2fr); 
}
// 表示每行有两列,列宽为50%,且每列宽度不小于100px
div{
    display: grid;
    grid-template-columns: 1fr 1fr minmax(100px, 1fr); 
}
// 表示每行有3列,列宽为100px 100px auto,第三列有浏览器自己决定长度
div{
    display: grid;
    grid-template-columns: 100px 1fr auto; 
}
  1. grid-row-gapgrid-column-gapgrid-gap属性:设置行/列间距
// 表示行间距=列间距=20px
div {
    grid-gap: 20px; // grid-gap: <grid-row-gap> <grid-column-gap>,第二个值可省略
}
  1. grid-template-areas属性:用于定义区域,网格线的命名会自动变成区域名-start, 区域名-end

  2. grid-auto-flow属性:与flex-direction类似,设置子元素的排序顺序,值为row/column/row-dense/column-dense

  • row/column: 表示按行/列排布,排不下的换行/列排布

  • row-dense/column-dense: 表示按行/列紧凑排布,当下一个排不下时会去找下一个能排下的元素,直至换行/列

  1. 单元格内布局 取值:centerstartendstretch(拉伸,默认值)
  • justify-items: 单元格内的水平位置;
  • align-items: 单元格内的垂直位置;
  • place-items: <align-items> <justify-items>
  1. 整个内容区域布局 取值有centerstartendstretchspace-aroundspace-betweenspace-evenly
  • justify-content: 整个内容区域在容器中的水平位置;
  • align-content: 垂直位置;
  • place-content: <align-content> <justify-content>

7.常用的有以上,其余的…………………………好多属性,再写也记不住了~ 用到的时候再记吧。

二、historyhash的区别

这两种都可以实现客户端改变视图的同时,不向后端发出请求。

1、hash模式

  1. 通过在URL锚点#后面拼接路由参数的方法,这种改变hash的方法不会引起浏览器重新加载页面
  2. 利用window.onhashchange事件,监听hash的更改,从而加载对应的页面(window.location.hash.substr(1))

2、history模式

  1. 利用H5 History Interface新增pushState()replaceState()方法,来记录历史路由栈
  2. 该模式下,一般刷新之后会报404错误,需要后端ng的配置
  3. pushStatereplaceState方法,只能导致history对象变化,浏览器不会向后端发送请求,也不会触发popstate事件(popstate事件是在点击浏览器前进后退按钮之后触发执行的)
  4. history模式下的路由监听使用popstate事件来实现

三、Map数据结构和WeakMap数据结构

1、Map

  1. Map结构是一种数组键值对格式,它跟对象明显不一样的点是,它不对值进行强制类型转换
  2. Map方法
    • let map = new Map(): 实例化一个Map数据结构
    • set()map.set('name', 'test')
    • get()map.get('name')
    • delete(): map.delete('name')
    • clear(): map.clear()
    • size: map.size // 获取长度 image.png
    • 遍历: map.forEach((value, key, self) => {}) image.png
    • Map转对象,通过Object.fromEntries(map)方法 image.png

2、WeakMap

  1. WeakMap方法:没有了Map的遍历、clear清除、获取长度size的方法,只保留了以下四个
    • delete()
    • set()
    • get()
    • has()
  2. Map不同的一点,WeakMap只接受对象作为键值
  3. WeakMap弱引用(对对象的弱引用是指当该对象应该被GC(Garbage Collection垃圾回收机制)回收时不会阻止GC的回收行为):当外部的引用被删除后,WeakMap内部的引用会相应的被GC垃圾回收
  4. WeakMap的使用场景: 可用于写DOM节点的监听事件,当DOM节点被删除后,WeakMap中对于该DOM节点的引用也会被垃圾回收,不容易造成内存泄漏

四、SetWeakSet

SetWeakSet的区别同MapWeakMap类似

1、Set:本身是一个构造函数,类似于数组,但是数组中的值是唯一、不重复的

  1. Set方法
    • add()
    • delete()
    • has()
    • clear()
    • size
    • keys(): 键名的遍历器
    • values(): 键值的遍历器
    • entries(): 键值对的遍历器
    • forEach(): 使用回调函数遍历每个成员
  2. 常用的使用场景:用于对数组的去重
let a = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,8,9,10,10,11];
let b = [2,3,4,5,3,2,1,32,2321,12121];
let set = new Set([...a, ...b])
// 输出set结果:Set(14) {1, 2, 3, 4, 5, …}
let array = Array.from(set)
// 输出array结果:(14) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 32, 2321, 12121]

2、WeakSet

WeakSet: 结构同Set类似,区别是其成员只能是对象,且为SetWeakSet,成员随时会消失,因此不支持遍历

  1. WeakSet方法,去除掉遍历方法以及size,只有以下3个方法
    • add()
    • delete()
    • has()
  2. WeakSet常用的使用场景:用于存储DOM节点,当节点被移除后,相应的WeakSet也会被垃圾回收,不容易造成内存泄漏

五、移动端布局

移动端布局下,meta标签的常用写法

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>

移动端的布局方法,常见的有以下几种:

1、rem布局

remem的区别是:rem是相对根元素font-size来布局,而em是相对父元素 设计思路:

  • 移动端屏幕尺寸规定为750px,设计稿尺寸为750px

  • 若将屏幕宽度分出为10份,每一份大小为 750/10 = 75

  • html根元素font-size: 设备宽度/75 + 'px',

    handleFontSizeRoot() {
        let width = document.documentElement.offsetWidth / 75;
        document.documentElement.style.fontSize = width + 'px';
    }
    
  • css布局时写法上:750px === 75rem, 100px === 10rem, 12px === 1.2rem

  • postcss:一种对css编译的工具,类似babel-loader,可安装postcss-pxtorem插件,将px转换成rem,该插件对于px的检测是区分大小写的(即,Px/PX/pX不会被转换成rem);

    (这个loader先简单提下,后面会有说明,具体可看下postcssscoped的转译)

2、@media媒体查询

  1. @media媒体类型查询,媒体类型取值有以下4个
  • all 所有设备
  • print 打印设备
  • screen 电脑屏幕、平板屏幕、移动端屏幕
  • speech
  1. @media关键字查询,常用关键字有以下几种:
  • max-width: 1000px 查询匹配宽度小于1000px
  • min-width: 750px 查询撇皮=宽度大于750px
  • and 与运算连接符
  • only 表示唯一
  • not 否运算连接符
  1. @media可以用在link标签上,用于按需加载css资源
    <link rel="stylesheet" href="css/1.css" media="(max-width:750px)"/>
    

3、百分比

  1. 直接使用百分比来布局,该方法下图片布局比较混乱

4、vhvw布局方法

  1. 使用过程中有问题:
  • IOS下,软键盘是叠在可视窗口上的
  • 安卓下,软键盘会撑开一定高度

六、postcssscoped的转译

七、文档流

1、会脱离文档流的布局方式

  1. float 浮动
  2. absolute 布局方式
  3. fixed 布局方式: 主要用于贴靠浮动

2、清除浮动的方法

  1. 父元素设置宽高自动撑起
  2. 浮动元素下新增一个空的同级元素,设置清除浮动样式:clear: both
  3. 浮动元素的父元素设置伪类::after ::before从而清除浮动

八、width offsetWidth clientWidth scrollWidth innerWidth的区别

  1. width: 可读写,通过style.width来修改之,返回带单位的字符串
  2. offsetWidth:只读属性,返回整数值,表示元素的实际宽度,offsetWidth = width + padding + border
  3. clientWidth: 可视区域的宽度
  4. scrollWidth:实际内容的宽度
  5. innerWidthwindow.innerWidth 表示浏览器窗口的内部宽度

九、height offsetHeight clientHeight scrollHeight innerHeight的区别

同上一点类似

十、for offor in 遍历器的区别

1、for of

  1. for(let i of arr) i 为键值value
  2. 可用于遍历字符串,遍历得到字符
  3. 无法直接遍历对象拿到键值,但可以通过Object.values Object.keys Object.entries来实现遍历

2、for in

  1. for(let i in arr) i 为键名key
  2. 可用于遍历字符串,遍历得到字符的索引值
  3. 可用于遍历对象,遍历得到对象的key

十一、重绘和回流

回流一定会触发重绘,重绘不一定会触发回流;

回流的代价会高于重绘。

1、回流

引起场景:当有元素宽高、布局、显示或隐藏,或元素内部的文字结构发生变化时,会引起回流(重新构建页面)

  1. 添加、删除DOM元素
  2. DOM元素发生位移
  3. DOM元素尺寸变化(包括border padding width height
  4. DOM元素文本更改
  5. 页面一开始渲染的时候
  6. 页面尺寸改变
  7. JS中获取DOM的偏移量属性,如offsetWidth clientWidth(相关原因后面有写)

2、重绘

当元素宽高、布局、显影等都未有更改,只是改变了元素的外观风格时,会引起重绘

  1. DOM元素样式更改(visibilitycolorbackground-color等)
  2. input数据框的变化
  3. css伪类

3、优化重绘和回流

  1. transform替换topleftmargin-topmargin-left这些位移属性
  2. opacityvisibility
  • visibility会引起重绘但不会引起回流
  • 只用opacity会引起回流
  • opacitytransform: translateZ/3d 不会产生回流和重绘
  1. 不要用jsdom元素设置样式等,直接用一个className
  2. 避免频繁用js获取dom的样式,如offsetWidth, clientWidth这些。浏览器有一个回流的缓冲机制,多个回流会保存在一个栈里面,当这个栈满了浏览器会一次性触发所有样式的更改切刷新这个栈。当获取dom的样式时,浏览器为了给到一个准确的答案会不停刷新这个缓冲栈,导致页面回流增加。
  3. 动画的速度按照业务需求定,必要时可以开启GPU加速
  4. 给需要频繁重绘和回流的节点单独设置图层,可设置成absolutefixed
  5. 避免频繁操作DOM,可通过cloneNode赋值DOM节点出来,更改完成后再replaceChild

4、16ms优化

大多数设备的刷新频率是60次/s,即没渲染一次要在1000ms/60次=16.6ms内完成,超出这个时间,页面的渲染会出现卡顿现象,影响用户体验

浏览器渲染页面的过程大致如下::

  • 解析HTML,生成DOM
  • 解析CSS,生成CSSOM
  • DOM树和CSSOM树结合,生成Render渲染树
  • Layout(回流)布局,根据窜蚺属,确定DOM元素在屏幕上显示的大小和位置
  • Paint(重绘) 绘制DOM元素文字、颜色、图像、边框和阴影等
  • Composite 渲染层合并,按照合理的顺序合并图层然后显示到屏幕上

十二、关于线上环境bug的及时跟进

**sentry错误日志监控**: 主要用于vue项目发生产之后的bug收集;

目前开发的时候我们可调试,但一旦发生产之后,若出现bug,开发人员没办法及时获取到bug复现场景,只能依靠用户的反馈,这点很不友好,所以引入sentry错误日志监控,至于搭建流程,具体可看下官网(外国网站,国内浏览很慢~需要VPN

十三、防抖和节流

1、防抖:

  1. 原理:事件触发后,延迟n秒再执行,n秒内重复触发,则重新设置定时器计时
  2. 实现方法:
  • 触发事件,清除定时器
  • 设置定时器n秒后执行
  1. 应用场景:input框边输入边调用接口搜索

2、节流:

  1. 原理:某个时间段内只触发一次事件(即使多次点击)
  2. 实现方法:
  • 判断flagtrue时,进入事件
  • 事件中 置flagfalse, 设置定时器
  • 定时器执行完成后,置flagtrue
  1. 应用场景:
  • button多次触发
  • 懒加载监听滚动条位置

十四、Promise的异常捕获如何实现

先不做说明,这个关于Promise的实现原理,下次补上

十五、webpack打包的步骤

具体可看下这两篇:

知乎文章1

知乎文章2

十六、webpack import原理

还在了解中,后面补充进来

十七、Vue3新出的composition API 跟 原本的option API有什么区别

首先,这两个的使用是不冲突的,需要使用哪个可供开发者自由选择。

十八、setTimeout跟Promise的执行顺序

这个问题是关于浏览器 JS引擎线程的事件循环机制,具体可看下我之前的文章