面经

  • 1、抢镜(某不知名小公司)
  • 2、兆百特(某不知名小公司)
  • 3、Boss直聘
    • 1、输入URL到页面展示
    • 2、addEventListener() 方法,事件监听
    • 2、缓存的Cache-Control的no-store和no-catch字段有什么区别?
    • 3、如何实现上传大文件好几百兆?
    • 4、生成一个随机数
    • 5、兄弟组件之间传值
    • 6、怎么动态切换组件
    • 7、如何取消请求
    • 8、Vue中的watch如何只监听一次
  • 4、高途
    • 1、闭包及其应用场景
    • 2、v-model语法糖
    • 3、Vue中的虚拟DOM
    • 4、v-for中key的作用,为什么只在循环中绑定,不绑定key会有什么问题
    • 5、js中的异步,js的异步有哪些方案?回调函数是啥?
    • 6、async/await原理
  • 5、Fabrique 束一科技&开果传媒
    • 1、项目
    • 2、小程序开发ios和安卓的适配
    • 3、Vue组件缓存
    • 4、Vue.set()的使用
    • 13、Vue实现面包屑
    • 14、vue.config.js配置
  • 5、北京塞勒斯科技(Sailors)
    • 1、CSS实现三角形
    • 2、CSS样式优化
    • 3、父子组件执行顺序
    • 4、history路由和hash路由区别
    • 5、移动端适配
  • 6、小冰
    • 1、CSS的定位
    • 2、居中的方案
    • 3、深拷贝、浅拷贝
    • 4、浏览器缓存的Etag怎么生成
    • 5、三栏布局的实现方式(左右宽度固定,中间自适应)
    • 6、普通函数和箭头函数的区别
  • 7、猿辅导
    • 1、BFC
    • 2、0.1+0.2 !== 0.3
    • 3、Etag和Last-Modified
    • 4、script标签的defer和async有什么不同
    • 5、typeof
    • 6、事件循环输出题
    • 7、https中的数字证书
    • 8、http1和http2的区别
  • 8、先胜业财
    • 1、ES6的新语法
    • 2、Vue.$nextTick
    • 3、Vuex使用及其数据双向绑定原理
    • 4、Vue2和Vue3数据双向绑定的原理
    • 5、浏览器的事件循环
  • 9、汇博科技
  • 10、字节跳动
    • 1、堆和栈
    • 2、MPX小程序框架的优点
    • 3、MPX可以自动对字体和页面做适配,了解原理吗?
    • 4、CSS预处理器
    • 5、小程序和H5的适配
  • 12、北京智慧星光
    • 1、Vue路由守卫
    • 2、路由传参数
    • 3、前端分页实现
    • 4、前端登录鉴权逻辑
    • 5、v-for和v-if的优先级
  • 13、拼多多
  • 14、领岳科技
    • 1、this指向的输出题
    • 2、异步输出顺序问题
  • 15、百度
    • 1、浏览器重绘重排
    • 2、深拷贝和浅拷贝以及其实现方式
    • 3、根据id和pid构造出树形结构
  • 16、米可世界
  • 17、优贝在线(音乐、K歌、社交APP)
    • 1、CSS有哪些可继承属性
    • 2、正则表达式

前端性能优化

1、抢镜(某不知名小公司)

  1. CSS的position的属性一共有多少种,他们对应的表现是什么?
  2. 你知道哪些本地存储的方案,他们各自的优缺点是什么?
  3. 你知道浏览器的缓存机制嘛?在你的项目中是如何设置缓存策略的?
  4. script标签的async属性和defer属性有什么作用?
  5. 从浏览器输入url到页面展示经历了什么?
  6. 在你的项目中用过哪些性能方面的优化?
  7. 你是如何保证前端应用的稳定行的?比如代码规范,数据监控?
  8. 你做过哪些前端提升人效的解决方案,怎么去评估它的效果?

Q:1、CSS的position的属性一共有多少种,他们对应的表现是什么?

A:

CSS position属性用于指定一个元素在文档中的定位方式。top、right、bottom、left 属性则决定了该元素的最终位置。

属性值 描述
absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。
fixed 生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。
relative 生成相对定位的元素,相对于其正常位置进行定位。因此,“left:20” 会向元素的 LEFT 位置添加 20 像素。
static 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
inhert 规定应该从父元素继承 position 属性的值。

Q:2、你知道哪些本地存储的方案,他们各自的优缺点是什么?
A:

浏览器的本地存储主要分为Cookie、WebStorage、IndexDB,其中WebStorage又可以分为localStorage和sessionStorage

  • Cookie:存放4KB左右、每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题、可设置失效时间,没有设置的话,默认是关闭浏览器后失效
  • localStorage:可以保存5MB的信息、仅在客户端(即浏览器)中保存,不参与和服务器的通信、除非被手动清除,否则将会永久保存。
  • sessionStorage:可以保存5MB的信息、仅在客户端(即浏览器)中保存,不参与和服务器的通信、 仅在当前网页会话下有效,关闭页面或浏览器后就会被清除。
  • IndexedDB:IndexedDB是运行在浏览器中的非关系型数据库, 本质上是数据库,绝不是和刚才WebStorage的 5M 一个量级,理论上这个容量是没有上限的。

Q:3、你知道浏览器的缓存机制嘛?在你的项目中是如何设置缓存策略的?
A:

浏览器缓存机制

浏览器缓存主要分为强缓存协商缓存
如何来检查是否命中缓存呢?通过相应的字段来进行,但是说起这个字段就有点门道了
强缓存
HTTP/1.0 :Expires

Expires: Wed, 22 Nov 2019 08:41:00 GMT

HTTP/1.1:Cache-Control

Cache-Control:max-age=3600

Cache-Control还有以下几个字段:

  • public: 客户端和代理服务器都可以缓存。因为一个请求可能要经过不同的代理服务器最后才到达目标服务器,那么结果就是不仅仅浏览器可以缓存数据,中间的任何代理节点都可以进行缓存。
  • private: 这种情况就是只有浏览器能缓存了,中间的代理服务器不能缓存。
  • no-cache: 跳过当前的强缓存,发送HTTP请求,即直接进入协商缓存阶段。
  • no-store:非常粗暴,不进行任何形式的缓存。
  • s-maxage:这和max-age长得比较像,但是区别在于s-maxage是针对代理服务器的缓存时间。
    值得注意的是,当Expires和Cache-Control同时存在的时候,Cache-Control会优先考虑。

协商缓存
强缓存失效之后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个tag,来决定是否使用缓存,这就是协商缓存。
具体来说,这样的缓存tag分为两种: Last-Modified 和 ETag。这两者各有优劣,并不存在谁对谁有绝对的优势,跟上面强缓存的两个 tag 不一样。
主要有Last-ModifiedETag两个字段。这两个字段都是服务端响应头中的字段

Last-Modified
即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。
浏览器接收到后,如果再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间。
服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:

如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
否则返回304,告诉浏览器直接用缓存。

ETag
ETag 是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。
浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。
服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:

如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
否则返回304,告诉浏览器直接用缓存。

Q:4、script标签的async属性和defer属性有什么作用?
A:
HTMl中的script中的async/defer有什么作用和区别
如果script标签是引用的外部js文件, 那就会有一个下载js文件这一过程, 为了不因为这个下载过程而阻塞页面解析与渲染, 我们需要一种机制来解决这一问题, 方法之一就是使用 defer和async属性

 <script defer src="./test1.js"></script>//console.log("defer是DOM载入完成后执行.")<script async src="./test2.js"></script>
// console.log("async是新开一个进程, 下载完成后就暂停主进程的解析, 执行下载的脚本.")
  1. 使用async不能保证脚本的执行顺序, 而是谁先下载完, 就先执行谁, 因此async适用于脚本之间没有依赖关系的情况. 反之再用defer;

  2. 如果一个scritp标签同时有defer和async属性, 则defer失效, script的行为由async决定;

  3. 在脚本中还是不能使用document.write()方法.

总结起来, defer和async区别在于, 前者是在html解析完毕后按顺序执行, 而async是单独下载, 完成后立即执行.


绿色(解析/parsing)停止的地方就是碰到script标签的地方,js文件下载完,执行之后,html文件才再次继续进行解析;

问题在于,如果js文件比较大,这样会极大的阻碍网页页面的生成,页面出于短暂长时间空白,看起来页面像是卡在了那里,这种情况是我们需要极力避免的。

async 属性告诉我们HTML解析器(parser),它可以在后台下载这个JS文件,并且它可以继续向下解析当js文件在后台下载的时候,之后,只要js文件一下载完毕,这个时候如果解析工作还没有完成,还在解析, 那么立马停下手头的解析工作,开始执行js文件,执行完之后,再恢复解析工作,继续向下解析;如果此时解析完了,那就更不用说了,直接开始执行js文件。

问题在于,如果你header里面有多个script标签,肯定从上到下有个顺序吧,如果彼此互相没有依赖都能独立执行,那还好说,如果存在依赖关系,那么此刻先执行哪个文件,后执行哪个文件是有要求的时候,那么我们就没办法控制,因为哪个文件先执行,完全取决于哪个文件先下载完毕,先下载完毕的就先执行,后下载完毕的就后执行,所以不可避免的就会乱序执行起来。


defer 属性和async有点像,async是js文件刚下载完毕就开始执行,而defer是等待 HTML的解析所有都完毕之后,才会进行js文件的执行,并且这个js文件的执行是按照script标签定义的顺序来执行的,所以这就和在body中的最末尾定义普通没有任何属性的多个script标签一样,从上到下按顺序开始执行,并且没有阻塞HTML文件的解析,所以defer这个属性的添加,完美的解决了async的问题,还有没有属性却还定义在header中script标签,阻塞html文件解析的情况。

Q:5、从浏览器输入url到页面展示经历了什么?
A:

从输入URL到看到页面发生了什么
主要有以下几个过程

  1. DNS解析
  2. 发起TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析
  6. 渲染页面
  7. 连接结束

域名解析:
DNS域名解析的过程
DNS解析视频讲解
如果某个用户正在用浏览器mail.baidu.com的网址,当你敲下回车键的一瞬间:

1、检查浏览器缓存中是否存在该域名与IP地址的映射关系,如果有则解析结束,没有则继续
2、到系统本地查找映射关系,一般在hosts文件中,如果有则解析结束,否则继续
3、到本地域名服务器去查询,有则结束,否则继续
4、本地域名服务器查询根域名服务器,该过程并不会返回映射关系,只会告诉你去下级服务器(顶级域名服务器)查询
5、本地域名服务器查询顶级域名服务器(即com服务器),同样不会返回映射关系,只会引导你去二级域名服务器查询
6、本地域名服务器查询二级域名服务器(即baidu.com服务器),引导去三级域名服务器查询
7、本地域名服务器查询三级域名服务器(即mail.baidu.com服务器),此时已经是最后一级了,如果有则返回映射关系,则本地域名服务器加入自身的映射表中,方便下次查询或其他用户查找,同时返回给该用户的计算机,没有找到则网页报错
8、如果还有下级服务器,则依此方法进行查询,直至返回映射关系或报错

TCP的三次握手

TCP四次挥手
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,假设客户端主动关闭,服务器被动关闭。

浏览器的渲染流程

  1. 解析 HTML 文件,构建 DOM 树,同时浏览器主进程负责下载 CSS 文件
  2. CSS 文件下载完成,解析 CSS 文件成树形的数据结构,然后结合 DOM 树合并成
    RenderObject 树
  3. 布局 RenderObject 树 (Layout/reflow),负责 RenderObject 树中的元素的尺寸,位置等计算
  4. 绘制 RenderObject 树 (paint),绘制页面的像素信息
  5. 浏览器主进程将默认的图层和复合图层交给 GPU 进程,GPU 进程再将各个图层合成(composite),最后显示出页面
  1. 解析HTML生成DOM树。
  2. 解析CSS生成CSSOM规则树。
  3. 解析JS,操作 DOM 树和 CSSOM 规则树。
  4. 将DOM树与CSSOM规则树合并在一起生成渲染树。
  5. 遍历渲染树开始布局,计算每个节点的位置大小信息。
  6. 浏览器将所有图层的数据发送给GPU,GPU将图层合成并显示在屏幕上。

Q:6、在你的项目中用过哪些性能方面的优化?
A:

https://juejin.cn/post/6892994632968306702

  • 减少http请求
  • 使用http2
  • 使用服务端渲染
  • 静态资源使用CDN
  • 将CSS放在文件头部,JS文件放在底部
  • 使用字体图标iconfont代替图片图标
  • 善用缓存,不重复加载相同的资源
  • 压缩文件
  • 图片优化(图片懒加载、响应式图片、调整图片大小、使用webp格式的图片)
  • 使用webpack按需加载代码,提取第三方库代码,减少ES6转ES5的冗余代码
  • 减少重绘重排
  • 使用事件委托
  • if-else对比switch
  • 使用防抖节流函数
  • 避免页面卡顿
  • 降低CSS选择器的复杂性
  • 使用 transform 和 opacity 属性更改来实现动画
  • 使用 flexbox 而不是较早的布局模型

arr.splice()

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

arr.reduce()
reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

const arr = [1, 2, 3, 4]
const initialValue = 0
const sum = arr.reduce((previousValue, currentValue, currentIndex, array) => {/*previousValue:上一次调用 callbackFn 时的返回值。在第一次调用时,若指定了初始值 initialValue,其值则为 initialValue,否则为数组索引为 0 的元素 array[0]。currentValue:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,其值则为数组索引为 0 的元素 array[0],否则为 array[1]。currentIndex:数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。array:用于遍历的数组。*/return previousValue + currentValue
}, initialValue)
console.log(sum);
// expected output: 10// arr.reduce()函数的参数
// 1、callbackFn
// 一个 “reducer” 函数,包含四个参数:
// 2、initialValue 可选
// 作为第一次调用 callback 函数时参数 previousValue 的值。若指定了初始值 initialValue,则 currentValue 则将使用数组第一个元素;
// 否则 previousValue 将使用数组第一个元素,而 currentValue 将使用数组第二个元素。
// 返回值
// 使用 “reducer” 回调函数遍历整个数组后的结果。

Q:7、你是如何保证前端应用的稳定行的?比如代码规范,数据监控?
A:

Q:你做过哪些前端提升人效的解决方案,怎么去评估它的效果?
A:

2、兆百特(某不知名小公司)

一下午面了三面,面过了感觉我不回去,然后没发offer!

3、Boss直聘

一面(1h)

  • 说说近期做的项目
  • 输入URL到页面展示经历了什么?
  • 缓存的Cache-Control的no-store和no-catch字段有什么区别?
  • 事件冒泡和事件捕获有什么区别?他俩的执行顺序?为什么是这样的顺序?
  • event.dateset.curTarget和…的区别?
  • 说说addeventListener形参,咋用的
  • 事件委托、事件代理
  • 生成一个随机数(-200 ,1)怎么用Math.random()
  • Vue兄弟节点数据传递的方案
  • Vue组件的动态切换
  • 自己有没有写过UI组件,在UI组件里怎么取到全局Vue实例
  • 表单提交,如果我要上传一个大文件,怎么整?分片、怎么分片、分片要注意啥
  • 怎么取消一个请求,fetch原声AJAX请求怎么取消
  • 事件循环,看题说输出顺序
  • CSS的布局、flex布局
  • 小程序的启动性能优化
  • 项目!、项目!说出自己项目遇到的问题、难点、如何克服、有哪些成就(项目需要好好梳理梳理)
  • iphone底部的小黑条适配
  • H5页面上有100000万条数据,需要下拉这样去看,怎么做优化
  • Vue项目怎么做性能优化?
  • 反问,问部门。

1、输入URL到页面展示

2、addEventListener() 方法,事件监听

事件冒泡和事件捕获区别?
事件冒泡:
假设我要点击的是div,点击后会一层一层的往上。

事件捕获:
事件捕获与事件冒泡完全相反。是从上至下到指定元素。

事件委托
利用事件冒泡和事件源对象进行处理
优点:
1、性能 不需要循环所有的元素一个个绑定事件
2、灵活 当有新的子元素时不需要重新绑定事件
我们有下面结构的一个列表:

<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>
</ul>

如果我们想实现当每个li点击自身时,都在控制台打印自己的内容,要怎么做呢?

按照我们之前的理解,肯定是先获取li标签,利用for循环给每个li标签添加点击事件。

但是当我们了解了事件冒泡和事件对象之后,我们有了更好的写法:

let ul = document.getElementsByTagName('ul')[0]
ul.onclick = function(e){console.log(e.target.innerText) // 1、 2、 3、 4、 5
}

addEventListener() 方法用来做事件监听

你可以使用 removeEventListener() 方法来移除事件的监听。

window.addEventListener("resize", function(){document.getElementById("demo").innerHTML = sometext;
});
element.addEventListener(event, function, useCapture);

第一个参数是事件的类型 (如 “click” 或 “mousedown”).
注意:不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。

第二个参数是事件触发后调用的函数。(回调函数)
event.target代表的是触发事件的元素,而event.currentTarget代表的是那个绑定了事件处理函数的元素。

当第三个参数设置为true就在捕获过程中执行,反之就在冒泡过程中执行处理函数
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。

可能值:
true - 事件句柄在捕获阶段执行
false false是默认值。事件句柄在冒泡阶段执行

DOM事件流如图:

由图可知捕获过程要先于冒泡过程

2、缓存的Cache-Control的no-store和no-catch字段有什么区别?

  • no-store:不进行任何形式的缓存
  • no-cache:每次都需要去服务端做校验,看是否已经过期,也就是绕过强缓存走协商缓存

3、如何实现上传大文件好几百兆?

面试官:请实现一个大文件上传

大文件上传

  • 前端上传大文件时使用 Blob.prototype.slice 将文件切片,并发上传多个切片,最后发送一个合并的请求通知服务端合并切片
  • 服务端接收切片并存储,收到合并请求后使用流将切片合并到最终文件
  • 原生 XMLHttpRequestupload.onprogress 对切片上传进度的监听
  • 使用 Vue 计算属性根据每个切片的进度算出整个文件的上传进度

断点续传

  • 使用 spark-md5 根据文件内容算出文件 hash
  • 通过 hash 可以判断服务端是否已经上传该文件,从而直接提示用户上传成功(秒传)
  • 通过 XMLHttpRequest 的 abort 方法暂停切片的上传
  • 上传前服务端返回已经上传的切片名,前端跳过这些切片的上传

4、生成一个随机数

  • Math.random //函数生成一个[0, 1)范围内的随机数
  • Math.floor(n) //向下取整,返回一个n的整数部分的数
  • Math.ceil(n) //向上取整,返回一个大于等于n的最小整数
function myRandom (a, b) {console.log(Math.floor(Math.random()*(b-a+1) + a))return Math.floor(Math.random()*(b-a+1) + a)
}
myRandom(80, 90)

5、兄弟组件之间传值

Vue组件之间的通信

1、bus总线传值

//bus.js
import Vue from 'vue';
export default new Vue;
//使用 兄弟A 传值
import bus from '路径'
bus.$emit('自定义事件名称',输出数据)
//使用 兄弟B 接值
import bus from '路径'
bus.on('自定义事件名',(res)=>{})

eventbus原理:
VUEeventBus可以用来进行任何组件之间的通信,我们可以把eventBus当成一个管道,这个管道两端可以接好多组件,两端的任何一个组件都可以进行通信。其实这个管道就是Vue实例,实例中的$on, $off, $emit方法来实现此功能。

2、常规子1传父->父传子2

3、vuex

父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners

兄弟组件通信: eventBus ; vuex

跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners

6、怎么动态切换组件

动态切换组件

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:

上述内容可以通过 Vue 的 元素加一个特殊的 is attribute 来实现:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

7、如何取消请求

1、从ajax到fetch、axios
2、Axios 如何取消重复请求?
3、使用 AbortController 取消 Fetch 请求和事件监听

XMLHttpRequest.abort()
如果请求已被发出,则立刻中止请求。
Axios 是一个基于 Promise 的 HTTP 客户端,同时支持浏览器和 Node.js 环境。它是一个优秀的 HTTP 客户端,被广泛地应用在大量的 Web 项目中。对于浏览器环境来说,Axios 底层是利用 XMLHttpRequest 对象来发起 HTTP 请求。如果要取消请求的话,我们可以通过调用 XMLHttpRequest 对象上的 abort 方法来取消请求

axios的请求如何取消?
而对于 Axios 来说,我们可以通过 Axios 内部提供的 CancelToken 来取消请求:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();axios.post('/user/12345', {name: 'semlinker'
}, {cancelToken: source.token
})source.cancel('Operation canceled by the user.'); // 取消请求,参数是可选的

此外,你也可以通过调用 CancelToken 的构造函数来创建 CancelToken,具体如下所示:

const CancelToken = axios.CancelToken;
let cancel;axios.get('/user/12345', {cancelToken: new CancelToken(function executor(c) {cancel = c;})
});cancel(); // 取消请求

8、Vue中的watch如何只监听一次

当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

watch: {// 每当 question 发生变化时,该函数将会执行question(newQuestion, oldQuestion) {if (newQuestion.indexOf('?') > -1) {this.getAnswer()}}
},

除了 watch 选项之外,你还可以使用命令式的 vm.$watch API。
$watch 返回一个取消侦听函数,用来停止触发回调:

const vm = app.mount('#app')const unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()

4、高途

  1. 闭包及其应用场景
  2. 问项目,最近做的哪些项目?用到了哪些技术栈?讲一讲
  3. v-model语法糖,及其原理。能在组件里面用v-model吗?
  4. 虚拟DOM,为什么要用虚拟DOM,虚拟DOM有什么好处?
  5. v-for循环中的key,为什么要绑定key,不绑定会有哪些问题?为什么只在循环中绑定key
  6. 讲一下JS的异步、异步有哪些方案?回调函数有了解吗?
  7. Vue中的高阶函数
  8. 未来职业规划(最近3-5年)
  9. async/await底层原理
  10. 最近项目中遇到哪些技术难点,你是怎么解决的?

解答:

1、闭包及其应用场景

闭包

闭包是指有权访问另一个函数作用域中变量的函数

var a = 0
function foo(){var b =14function fo(){console.log(a, b)}fo()
}
foo()

这里的子函数 fo 内存就存在外部作用域的引用 a, b,所以这就会产生闭包
闭包的应用:

  • 封装私有变量
  • 防抖、节流
  • 经典场景-return回一个函数
  • 函数作为参数(将闭包作为函数的参数执行)
  • 使用回调函数就是在使用闭包

2、v-model语法糖

1、面试官:你真的了解v-mode吗?
2、v-model可以在组件中用吗?

3、Vue中的虚拟DOM

面试官:谈谈你对虚拟DOM的理解
Vue核心之虚拟DOM

4、v-for中key的作用,为什么只在循环中绑定,不绑定key会有什么问题

5、js中的异步,js的异步有哪些方案?回调函数是啥?

其实回调函数就是异步编程的一种解决方案

js中的异步解决方案

6、async/await原理

原理

5、Fabrique 束一科技&开果传媒

  1. 讲讲最近的项目和用到的技术栈
  2. 小程序中开发完之后用安卓和ios有没有什么不一样的地方
  3. Vue组件缓存,怎么在进入和离开缓存组件的时候做一些事情
  4. Vue.set怎么用(如果我更新了数据,发现视图没更新)
  5. 这么多筛选框重置,可以把对象重置为空,但是如果有默认值怎么整?
  6. 小程序多张图片上传怎么整
  7. Vue表格的分页
  8. H5的触底加载怎么实现的,具体的实现方式,有没有做什么优化
  9. Vue组件之间的通信
  10. 我从列表页走到详情页, 详情页更新,列表页怎么也跟着更新
  11. Vue菜单权限控制(怎么实现的,具体方法说一下)
  12. 有没有从0搭建过一个项目,除了默认的配置Vue-cli需要做哪些配置

1、项目

讲项目,讲技术栈

2、小程序开发ios和安卓的适配

兼容性问题

  • 底部小黑条适配
  • 页面栈不能超过十层
  • 闪光灯按钮在ios和安卓显示不一样
  • ios的date格式为2022/04/15 08:37:56,而安卓不是

3、Vue组件缓存

封装vue组件的一些小技巧
keep-alive:有activated 和 deactivated两个生命周期方法
使用方式:

// App.vue
<div class="app"><keep-alive><router-view v-if="$route.meta.keepAlive"></router-view></keep-alive><router-view v-if="!$route.meta.keepAlive"></router-view>
</div>

4、Vue.set()的使用

在我们使用vue进行开发的过程中,可能会遇到一种情况:当生成vue实例后,当再次给数据赋值时,有时候并不会自动更新到视图上去; 当我们去看vue文档的时候,会发现有这么一句话:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。 如下代码,给 student对象新增 age 属性

data () {return {student: {name: '',sex: ''}}
}
mounted () { // ——钩子函数,实例挂载之后this.student.age = 24
}

受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。
正确写法:this.$set(this.data,”key”,value’)

mounted () {this.$set(this.student,"age", 24)
}

13、Vue实现面包屑

Vue实现面包屑

14、vue.config.js配置

const webpack = require('webpack')
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const BundleAnalyzerConfig = process.env.npm_config_report ? [new BundleAnalyzerPlugin()] : []
const path = require('path')module.exports = {publicPath: './',filenameHashing: true,devServer: {host: 'local.intra.xiaojukeji.com',port: '8777',hot: true, // 开启热更新,提高开发效率headers: {'Access-Control-Allow-Origin': '*'},// 配置代理proxy: {'/api': {target: 'http://czp-test.intra.xiaojukeji.com', // 想要访问接口域名changeOrigin: true, // 开启跨域,在本地创建一个虚拟服务,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据交互就不会有问题pathRewrite: {'^/api': '' // 利用这个地面的值拼接上target里面的地址}}}},configureWebpack: {devtool: 'source-map',plugins: [new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),new HtmlWebpackExternalsPlugin({externals: [{module: 'waterMark',entry: 'https://sec-aegisfe.didistatic.com/static/aegisfe/water-mark1.0.js?v=' + Date.now(),global: 'waterMark'}]}),...BundleAnalyzerConfig],optimization: {splitChunks: {chunks: 'all',maxInitialRequests: 10,maxAsyncRequests: 10,minSize: 30 * 1024,minChunks: 1,name: true,cacheGroups: {'chunk-vendors_1': {name: 'chunk-vendors_1',test: /[\\/]node_modules[\\/](mime-db|elliptic|lodash|asn1.js|core-js)/,priority: -1},'chunk-vendors_2': {name: 'chunk-vendors_2',test: /[\\/]node_modules[\\/](xgplayer|minio|moment|zrender)/,priority: -2},echarts: {name: 'echarts',test: /[\\/]node_modules[\\/]echarts/,priority: -2},vue: {name: 'vue',test: /[\\/]node_modules[\\/](vue|vuex)/,priority: -2},antd: {name: 'antd',test: /ant-design/,priority: -2},iview: {name: 'iview',test: /[\\/]node_modules[\\/]iview/,priority: -2}}},runtimeChunk: {name: entrypoint => `runtime-${entrypoint.name}`}},resolve: {alias: {'@src': path.resolve('./src'),'@api': path.resolve('./src/api'),'@assets': path.resolve('./src/assets'),'@common': path.resolve('./src/common'),'@components': path.resolve('./src/components'),'@router': path.resolve('./src/router'),'@store': path.resolve('./src/store'),'@views': path.resolve('./src/views')}}},productionSourceMap: false,chainWebpack: config => {config.plugin('html').tap(args => {args[0].title = '车载屏管理系统'return args})}
}

5、北京塞勒斯科技(Sailors)

  • CSS实现三角形
  • 输入URL到页面展示
  • let、const区别
  • 箭头函数和普通函数
  • 组件封装的度,什么时候才会去封装组件
  • Vue父子组件的传值
  • Vue父子组件的挂载顺序
  • hash路由和history路由的区别
  • js的事件循环机制
  • 移动端适配(媒体查询、如果移动端页面放到浏览器中怎么适配)
  • 移动端1px解决方案
  • 父元素塌陷解决方案
  • http和https的区别
  • post和get区别
  • get请求怎么实现跳过缓存直接请求最新的数据
  • Vue的优点缺点
  • Vue2和Vue3
  • 非数组怎么转化为数组,用哪个API(Array.from)
  • 写CSS样式的时候怎么做性能优化
  • Vue性能优化
  • 前端有很多非常大的图片是怎么优化的?
  • 前端的设计模式(单例模式、发布者模式、发布订阅者模式)
  • 三栏布局(左右固定,中间自适应)
  • 有没有做过组内技术分享
  • 自己平常如何学习的

1、CSS实现三角形

思路:给div盒子设置宽高为0,然后设置border的宽度,然后给任意三边的颜色设置为transparent即可分别实现任一方向的三角形。

  .sanjiao {width: 0;height: 0;border-top: 100px solid #f00;border-right: 100px solid #0f0;border-bottom: 100px solid #00f;border-left: 100px solid #ff0;}

上述代码实现的效果如下:

然后我们可以通过给任意三边的颜色设置为 transparent 即可分别实现任一方向的三角形。通过设置某条边的宽度比其它边宽,来调整三角形的高度。

.triangle {width: 0;height: 0;border: 100px solid transparent;border-bottom: 200px solid #0ff;
}

实现效果如下:

等边三角形:

width: 0;
height: 0;
border-left: 69px solid transparent;
border-right: 69px solid transparent;
border-bottom: 120px solid skyblue;

效果如下:

2、CSS样式优化

前端性能优化

  • 使用简写 p { margin: 1px 2px 3px 4px; }
  • 用CSS替换图片
  • 使用颜色快捷方式
target { background-color: #ffffff; }
target { background: #fff; }
  • 删除不必要的0和单位
padding: 0.2em;
margin: 20.0em;
avalue: 0px;
// 优化后
padding: .2em;
margin: 20em;
avalue: 0;

3、父子组件执行顺序

加载渲染过程

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

更新过程

父beforeUpdate->子beforeUpdate->子updated->父updated

销毁过程

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

4、history路由和hash路由区别

history的一些API
hash路由和history路由的区别
Vuerouter两种模式的区别

  • hash模式是通过改变锚点(#)来更新页面URL,并不会触发页面重新加载,我们可以通过window.onhashchange监听到hash的改变,从而处理路由。
  • history模式是通过调用window.history对象上的一系列方法来实现页面的无刷新跳转。

5、移动端适配

面试官:你了解过移动端适配嘛?


6、北京红棉小冰科技有限公司


6、小冰

  • 居中的方案
  • CSS的定位,fixd定位有没有特殊情况
  • 深拷贝、浅拷贝、深拷贝实现方式
  • JSON.parse(JSON.stringfy())实现深拷贝有什么问题
  • 普通函数和箭头函数有什么区别
  • 提到了this,说说this的指向
  • 浏览器的缓存,缓存Etag的计算规则,是根据啥生成的
  • …展开运算符都可以操作哪些数据类型

1、CSS的定位

position的含义是指定位类型,取值类型可以有:static、relative、absolute、fixed、inherit和sticky,这里sticky是CSS3新发布的一个属性。

最容易忽略的属性position: sticky
fixed定位的一些特殊情况

2、居中的方案

居中的解决方案

3、深拷贝、浅拷贝

深拷贝与浅拷贝

  • 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象
  • 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

赋值和深/浅拷贝的区别

这三者的区别如下,不过比较的前提都是针对引用类型:

  • 当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。

  • 浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。

  • 深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。

浅拷贝的实现方式

  • Object.assign()
  • 函数库lodash的_.clone方法
  • 展开运算符…

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。

let obj1 = { person: {name: "kobe", age: 41},sports:'basketball' };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1); // { person: { name: 'wade', age: 41 }, sports: 'basketball' }

该函数库也有提供_.clone用来做 Shallow Copy,后面我们会再介绍利用这个库实现深拷贝。

var _ = require('lodash');
var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f);// true

展开运算符是一个 es6 / es2015特性,它提供了一种非常方便的方式来执行浅拷贝,这与 Object.assign ()的功能相同。

let obj1 = { name: 'Kobe', address:{x:100,y:100}}
let obj2= {... obj1}
obj1.address.x = 200;
obj1.name = 'wade'
console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }

深拷贝实现方法

  • JSON.parse(JSON.stringify())
  • lodash的_.cloneDeep
  • jQuery.extend()
  • 手写递归方法
let arr = [1, 3, {username: ' kobe'
}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan';
console.log(arr, arr4)

这也是利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

JSON.parse(JSON.stringify(obj))深拷贝的问题

  1. 如果obj里面存在时间对象,JSON.parse(JSON.stringify(obj))之后,时间对象变成了字符串。
  2. 如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象。
  3. 如果obj里有函数,undefined,则序列化的结果会把函数, undefined丢失。
  4. 如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null。
  5. JSON.stringify()只能序列化对象的可枚举的自有属性。如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor
  6. 如果对象中存在循环引用的情况也无法正确实现深拷贝。
function Person (name) {this.name = 20
}
const lili = new Person('lili')
let a = {data0: '1',date1: [new Date('2020-03-01'), new Date('2020-03-05')],data2: new RegExp('\\w+'),data3: new Error('1'),data4: undefined,data5: function () {console.log(1)},data6: NaN,data7: lili
}let b = JSON.parse(JSON.stringify(a))
console.log(b)

var _ = require('lodash');
var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
var $ = require('jquery');
var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
// 可以避免循环引用
function deepClone (obj, hash = new WeakMap()) {if (hash.has(obj)) {// 如果已经有这个对象,直接返回这个对象return hash.get(obj)}const targetObj = Array.isArray(obj) ? [] : {}hash.set(obj, targetObj)for (let i in obj) {if (obj.hasOwnProperty(i)) {if (typeof obj[i] === 'object') {targetObj[i] = deepClone(obj[i], hash)} else {targetObj[i] = obj[i]}}}return targetObj
}

4、浏览器缓存的Etag怎么生成

nginx 中 etag 由响应头的 Last-ModifiedContent-Length 表示为十六进制组合而成。

$ curl --head 10.97.109.49
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Tue, 10 Dec 2019 06:45:24 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 23 Apr 2019 10:18:21 GMT
Connection: keep-alive
ETag: "5cbee66d-264"
Accept-Ranges: bytes

5、三栏布局的实现方式(左右宽度固定,中间自适应)

  1. 使用浮动实现
  2. 使用绝对定位实现三栏布局
  3. 使用flexBox实现三栏布局
  4. 使用table实现解决三栏布局
  5. 使用grid实现三栏布局
// 1、前2种的html布局
<div class="outer"><div class="left"></div><div class="right"></div><div class="center"> this is center</div>
</div>
// 2、后四种的html布局
<div class="outer"><div class="left"></div><div class="center"> this is center</div><div class="right"></div>
</div>

使用float布局

左右中三个盒子,左右宽度各300,并且左右浮动

.outer div{min-height: 200px;
}
.left {float: left;width: 300px;background-color: pink;
}
.right {float: right;width: 300px;background-color: skyblue;
}
.center {background-color: #ccc;
}

使用position定位

三个盒子都绝对定位,中间盒子左右各定位300,左盒子左边0,右盒子右边0

.outer div{min-height: 200px;position: absolute;
}
.left {left: 0;width: 300px;background-color: pink;
}
.right {right: 0;width: 300px;background-color: skyblue;
}
.center {right: 300px;left: 300px;background-color: #ccc;
}

使用flex布局

外层盒子flex布局,内层盒子中间flex:1,其它的固定宽度300px

.outer {display: flex;min-height: 200px;
}
.left {width: 300px;background-color: pink;
}
.right {width: 300px;background-color: skyblue;
}
.center {flex: 1;background-color: #ccc;
}

使用table布局

需要给外层盒子定义display:table,内层盒子定义diplay:table-cell,再分别给左右宽度即可,中间就可以自适应

.outer {display: table;width: 100%;min-height: 200px;
}
.outer div{display: table-cell;
}
.left {width: 300px;background-color: pink;
}
.right {width: 300px;background-color: skyblue;
}
.center {background-color: #ccc;
}

grid布局

.outer {display: grid;grid-template-rows: 400px;grid-template-columns: 300px auto 300px;
}
.left {background-color: pink;
}
.right {background-color: skyblue;
}
.center {background-color: #ccc;
}

6、普通函数和箭头函数的区别

都2022了还不知道箭头函数和普通函数的区别

7、猿辅导

  • 说一下BFC及其应用,触发BFC的方法
  • 为啥0.1+0.2 !== 0.3,js浮点数采用什么格式
  • 浏览器的缓存机制,Last-Modified和Etag为啥会有两个,用Last-Modified会有什么问题吗?
  • script标签的defer和async有什么不同?如果是很多歌defer和很多和async标签,他们的执行顺序
  • typeof究竟可以判断出哪些数据类型,不能判断出哪些数据类型
  • 浏览器事件循环机制中的生命周期方法
  • 事件循环机制、一道输出题
  • 公司小程序MPX跟其它框架相比有哪些优点
  • jsBridge的一个原理,怎么通信
  • 手写深拷贝,支持基本数据类型、Array,Object、RegExp、Error、Map、Set、Symbol、

1、BFC

BFC 全称:Block Formatting Context, 名为 “块级格式化上下文”。
W3C官方解释为:BFC它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用,当涉及到可视化布局时,Block Formatting Context提供了一个环境,HTML在这个环境中按照一定的规则进行布局。
简单来说就是,BFC是一个完全独立的空间(布局环境),让空间里的子元素不会影响到外面的布局。那么怎么使用BFC呢,BFC可以看做是一个CSS元素属性

怎么触发BFC?

  • overflow:hidden
  • 用 overflow:hidden 和 overflow:auto overflow:scroll overflow:overlay 都可以创建
  • display: inline-block
  • position: absolute
  • position:fixed
  • display:table-cell
  • display:flex

BFC有哪些规则?

  • BFC就是一个块级元素,块级元素会在垂直方向一个接一个的排列
  • BFC就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签
  • 垂直方向的距离由margin决定, 属于同一个BFC的两个相邻的标签外边距会发生重叠
  • 计算BFC的高度时,浮动元素也参与计算

可以用来解决哪些问题

  • 清除浮动
  • 避免margin重叠

margin重叠的规则?

margin同正,则取最大值;
margin同负,则取最小值;
margin一正一负,则取二者之和。

2、0.1+0.2 !== 0.3

在做算术运算时,JS 会先把十进制数转换成二进制数后再计算,十进制小数转二进制数的方式是 x 2 取整,0.1 和 0.2 的二进制数是个无限循环小数。
而 JS 中表示一个数字只有 64 位,其中精度位(有效数位)只有 52 位,所以当出现无限循环小数时,会通过 0 舍 1 入 的规则截取前 52 位(类似十进制的四舍五入),这样导致了精度位的丢失。0.1 实际参与计算的数变大了,0.2 参与计算的数变小了,所以运算结果不一定等于 0.3。

console.log( 0.1 + 0.2) //0.30000000000000004

为什么0.1+0.2 != 0.2
彻底搞懂为什么0.1+0.2 != 0.3

3、Etag和Last-Modified

Etag主要为了解决Last-Modified无法解决的一些问题:

  1. 一些文件也许周期性的更改,但是它的内容并不改变(仅仅改变的是修改时间),这个时候我们不希望客户端认为这个文件被修改了,而重新获取资源.
  2. 某些文件修改非常频繁,比如在秒一下的时间内进行修改(比如1s内修改了N次),If-Modified-Since能检查到的粒度是秒级的,这种修改是无法判断的(或者说UNIX记录MTIME只能精确到秒)

4、script标签的defer和async有什么不同

defer:这个属性表示脚本在执行的时候不会改变页面的结构。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在script元素上设置defer属性,相当于告诉浏览器立即下载,但延迟执行。
async:async属性与defer类似。当然,它们两者也都只适用于外部脚本,都会告诉浏览器立即开始下载。不过,与defer不同的 是,标记为async的脚本并不保证能按照它们出现的次序执行。
若有多个script含defer属性,推迟执行的脚本不一定总会按顺序执行或者在DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本。

5、typeof

typeof只能准确判断原始数据类型和函数,无法精确判断出引用数据类型(统统返回 object)。有一点需要注意,调用typeof null返回的是object,这是因为特殊值null被认为是一个对空对象的引用(也叫空对象指针)。

console.log(typeof 666); // number
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof NaN) // number
console.log(typeof Symbol()); // symbol
console.log(typeof '1233') // string
console.log(typeof 1n); // bigint
console.log(typeof function name() {}); // functionconsole.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof new String('xxx')); // objectconsole.log(typeof null); // objectconsole.log(typeof new RegExp()) // object
console.log(typeof new Error()) // objectconsole.log(typeof new Map()) // object
console.log(typeof new WeakMap()) // objectconsole.log(typeof new Set()) // object
console.log(typeof new WeakSet()) // objectfunction getType (num) {return Object.prototype.toString.call(num).toLowerCase().substring(8, Object.prototype.toString.call(num).length-1)
}
console.log('------------------')
console.log(getType([])); // array
console.log(getType({})); // object
console.log(getType(new String('xxx'))); // stringconsole.log(getType(null)); // nullconsole.log(getType(new RegExp())) // regexp
console.log(getType(new Error())) // errorconsole.log(getType(new Map())) // map
console.log(getType(new WeakMap())) // weakmapconsole.log(getType(new Set())) // set
console.log(getType(new WeakSet())) // weakset

6、事件循环输出题

事件循环


console.log('script start')
async function async1() {await async2() // await后面是简单的输出console.log('async1 end')
}async function async2() {console.log('async2 end')
}async1()setTimeout(function() {console.log('setTimeout')
}, 0)new Promise(resolve => {console.log('Promise')resolve()
})
.then(function() {console.log('promise1')
})
.then(function() {console.log('promise2')
})console.log('script end')// script start
// async2 end
// Promise
// script end
// async1 end
// promise1
// promise2
// setTimeout
console.log('script start')async function async1() {await async2()console.log('async1 end')
}
async function async2() {console.log('async2 end')return Promise.resolve().then(()=>{console.log('async2 end1')})
}
async1()setTimeout(function() {console.log('setTimeout')
}, 0)new Promise(resolve => {console.log('Promise')resolve()
})
.then(function() {console.log('promise1')
})
.then(function() {console.log('promise2')
})console.log('script end')
script start
async2 end
Promise
script end
async2 end1
promise1
promise2
async1 end
setTimeout

7、https中的数字证书

https中的数字证书

8、http1和http2的区别

  • HTTP2解析速度快
  • 多路复用
  • 首部压缩
  • HTTP2可以给请求设置优先级
  • 流量控制
  • 服务器推送
  • 采用二进制协议

采用二进制协议
HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为”帧”:头信息帧和数据帧。二进制协议解析起来更高效、“线上”更紧凑,更重要的是错误更少。
服务器解析 HTTP1.1 的请求时,必须不断地读入字节,直到遇到分隔符 CRLF 为止。而解析 HTTP2 的请求就不用这么麻烦,因为 HTTP2 是基于帧的协议,每个帧都有表示帧长度的字段。


多路复用
HTTP1.1 如果要同时发起多个请求,就得建立多个 TCP 连接,因为一个 TCP 连接同时只能处理一个 HTTP1.1 的请求。
在 HTTP2 上,多个请求可以共用一个 TCP 连接,这称为多路复用。同一个请求和响应用一个流来表示,并有唯一的流 ID 来标识。
多个请求和响应在 TCP 连接中可以乱序发送,到达目的地后再通过流 ID 重新组建。


首部压缩
HTTP 协议是没有状态,导致每次请求都必须附上所有信息。所以,请求的很多头字段都是重复的,比如Cookie,一样的内容每次请求都必须附带,这会浪费很多带宽,也影响速度。
对于相同的头部,不必再通过请求发送,只需发送一次;
HTTP/2 对这一点做了优化,引入了头信息压缩机制;
一方面,头信息使用gzip或compress压缩后再发送;
另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,产生一个索引号,之后就不发送同样字段了,只需发送索引号。


服务器推送
HTTP2 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。
例如当浏览器请求一个网站时,除了返回 HTML 页面外,服务器还可以根据 HTML 页面中的资源的 URL,来提前推送资源。


http和https的区别

  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
  • HTTP和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
  • HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

const a = new Promise((resolve, reject) => {console.log('promise1')resolve()}).then(() => {console.log('promise2')})setTimeout(() => {console.log('timeout')})const b = new Promise(async (resolve, reject) => {await aconsole.log('after1')await bconsole.log('after2')resolve()})console.log('end')

8、先胜业财

  • Vue中diff算法(这个一定要搞懂)
  • 主要用到哪些ES6新语法
  • vue.$nextTick用法
  • Vuex怎么做到双向绑定的
  • Proxy代理怎么做到监听改变的
  • webpack的打包构建过程
  • webpack的热更新原理
  • promise.all()
  • 数组去重有哪些方案
  • 本地代理跨域的原理

1、ES6的新语法

  • let、const

  • 箭头函数 =>
    箭头函数没有自己的arguments、没有prototype属性、不能作为构造函数、没有自己的this,箭头函数的this指向即使使用call、apply、bind也无法改变

  • Map、Set数据结构

  • iterator迭代器
    对于可迭代的数据解构,ES6在内部部署了一个[Symbol.iterator]属性,它是一个函数,执行后会返回iterator对象(也叫迭代器对象),而生成iterator对象[Symbol.iterator]属性叫iterator接口,有这个接口的数据结构即被视为可迭代的
    数组中的Symbol.iterator方法(iterator接口)默认部署在数组原型上:

    默认部署iterator接口的数据结构有以下几个,注意普通对象默认是没有iterator接口的(可以自己创建iterator接口让普通对象也可以迭代)
    Array
    Map
    Set
    String
    TypedArray(类数组)
    函数的 arguments 对象
    NodeList 对象

    next方法返回又会返回一个对象,有value和done两个属性,value即每次迭代之后返回的值,而done表示是否还需要再次循环,可以看到当value为undefined时,done为true表示循环终止
    可迭代的数据结构会有一个[Symbol.iterator]方法
    [Symbol.iterator]执行后返回一个iterator对象
    iterator对象有一个next方法
    执行一次next方法(消耗一次迭代器)会返回一个有value,done属性的对象

  • 解构赋值

let  { res } = { res: 'msg' }
  • 剩余/扩展运算符
let arr = [1,2,3,4]
[...arr] // [1,2,3,4]
  • for of循环
  • Promise
  • ES6的Module
  • 函数默认值
function func1 (a =1) {}
  • Proxy

2、Vue.$nextTick

Vue.$nextTick你真的懂了吗???

this.$ nextTick–将回调延迟到下次DOM更新循环之后执行。
在修改数据之后立即使用它,然后等待DOM更新。官方给出的this.$nextTick的作用是:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
Vue. $nexttick主要用来获取数据改变之后的dom结构,放在其回调函数中的操作不会立即执行,而是等数据更新,DOM更新完之后才开始执行,这样拿到的是最新的数据

3、Vuex使用及其数据双向绑定原理

  • State
    用来存储共享的数据属性或状态
    可以使用mapState 辅助函数简化写法
  • Getters
    相当于计算属性,它的返回值会根据它的依赖被缓存起来,只有依赖值发生了变化才会重新计算。
    Getter接受state作为第一个参数
    可以使用mapGetters辅助函数简化写法
  • Mutations
    必须为同步函数
    在组件中使用this.$store.commit(‘xx’)来触发
    可以使用mapMutations辅助函数简化写法
  • Actions
    Action提交的是mutation,由mutation中的函数来修改state中的属性或状态
    可以包含任意异步操作
    在组件中使用this.$dispath(‘xx’)来触发
    可以使用mapActions辅助函数简化写法
  • Modules
    允许将store分割成模块,每个模块拥有自己的state,getters,mutation,action

Vue 主要通过以下 4 个步骤来实现数据双向绑定的:

  • 实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
  • 实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
  • 实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
  • 实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。

4、Vue2和Vue3数据双向绑定的原理

Vue2和Vue3的数据双向绑定
Vue数据双向绑定
Object.defineProperty监听的一些缺点:

  1. 一次只能对一个属性进行监听,需要遍历来对所有属性监听。这个我们在上面已经解决了。
  2. 在遇到一个对象的属性还是一个对象的情况下,需要递归监听。
  3. 对于对象的新增属性,需要手动监听
  4. 对于数组通过push、unshift方法增加的元素,也无法监听

5、浏览器的事件循环

在有宏任务和微任务的概念加入后,JS代码的整体执行逻辑变为:

  1. 得到的JS代码进入主线程
  2. 判断遇到的代码:如果是同步代码则进入步骤 3;如果是异步代码则进入步骤 4。
  3. 同步代码直接进入主线程执行。
  4. 对异步代码进行分类:如果是promise,则new promise以及接受的函数参数立即执行,then和catch的回调函数进入 微任务的Event Queue;如果是setTimeout或者setInterval(需要达到指定时间),则将回调函数注册到 宏任务的Event Queue。
    5.JS引擎判断主线程是否为空,如果为空,则读取 微任务Event Queue 中所有的消息,并依次执行。执行完毕后进入步骤 6。
    主线程和微任务 Event Queue 都为空后,读取 宏任务Event Queue 中的第一个消息进入主线程执行。执行完毕后进入步骤 5。

9、汇博科技

  • Vue3系统学习过吗?
  • webpack的基本数据类型
  • 一些数据输出题(this指向,作用域之类的)
  • Vue2的数据双向绑定,有哪些问题,Vue3的数据双向绑定的原理
  • TS用过吗
  • webpack常用的一些配置

10、字节跳动

  • 堆与栈的区别(内存是如何分配释放的)
  • MPX与其它小程序框架和原生的对比,有什么优点
  • 适配,小程序适配、H5的适配
  • 小程序线上环境有跨域问题吗?没有,因为不是在浏览器运行的
  • 小程序如何对请求的地址进行过滤?通过微信后台配置请求地址白名单
  • 本地如何与服务端联调:node中间层反向代理
  • 刚说MPX可以跨平台输出,了解背后的原理吗?
  • MPX可以自动对字体和页面做适配,了解原理吗?
  • 看你简历上写的有Sass、less、Stylus,你最喜欢用哪个?说说为啥各自有什么特点?
  • CSS预处理器怎么对CSS样式做兼容的 --webkit等开头的,怎么做兼容
  • 数据类型有哪些?基本数据类型、引用数据类型,延伸出堆栈区别
  • 在数组原型上写一个sum,api实现数组内数字求和[1, 2, 3].sum() 返回6
  • 手写promise.all
  • 求二叉树路径上的数字之和

1、堆和栈

堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别:

  1. 管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;
  2. 生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。
  3. 空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小64bits的Windows默认1M,64bits的Linux默认10M;
  4. (5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

2、MPX小程序框架的优点

滴滴开源小程序框架 MPX
MPX
Mpx是一款致力于提高小程序开发体验的增强型小程序框架,通过Mpx,我们能够以最先进的web开发体验(Vue + Webpack)来开发生产性能深度优化的小程序,Mpx具有以下一些优秀特性:

  1. 数据响应是Mpx运行时增强的核心能力,该能力让用户在小程序开发中能够像Vue中一样使用watch和computed特性,并且用直接赋值的方式操作数据驱动视图更新,而不需要手动调用setData方法,换言之框架接管了小程序中的setData调用。
  2. 数据响应特性(watch/computed)
  3. 增强的模板语法(动态组件/样式绑定/类名绑定/内联事件函数/双向绑定等)
  4. 深度性能优化(原生自定义组件/基于依赖收集和数据变化的setData)
  5. Webpack编译(npm/循环依赖/Babel/ESLint/css预编译/代码优化等)
  6. 单文件组件开发
  7. 状态管理(Vuex规范/多实例/可合并)
  8. 跨团队合作(packages)
  9. 逻辑复用能力(mixins)
  10. 脚手架支持
  11. 小程序自身规范的完全支持
  12. 支付宝小程序的支持

3、MPX可以自动对字体和页面做适配,了解原理吗?

designWidth

设计稿宽度,单位为px。默认值为750px。

mpx会基于小程序标准的屏幕宽度baseWidth 750rpx,与option.designWidth计算出一个转换比例transRatio

转换比例的计算方式为transRatio = (baseWidth / designWidth)。精度为小数点后2位四舍五入

所有生效的rpx注释样式中的px会乘上transRatio得出最终的rpx值

/* 转换前:designWidth = 1280 */
.btn {width: 200px;height: 100px;
}/* 转换后: transRatio = 0.59 */
.btn {width: 118rpx;height: 59rpx;
}

4、CSS预处理器

CSS预处理器
CSS预处理器Sass为主
主要有变量、常量、嵌套、混入(@mixin)、函数等功能
CSS预处理器主要有Sass、Less、Stylus
Less 的基本语法属于CSS 风格
Sass,stylus 相比之下更激进一些, 可以利用缩进,空格和换行来减少需要输入的字符
不过区别在于 Sass, stylus同时兼容CSS风格的代码

5、小程序和H5的适配

H5页面适配安全区

body {padding: constant(safe-area-inset-top) constant(safe-area-inset-right)              constant(safe-area-inset-bottom) constant(safe-area-inset-left);  // constant在iOS<11.2的版本中生效   padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);     //env在iOS>=11.2的版本中生效
}

延伸: meta标签有一个属性,叫viewport-fit,顾名思义,就是网页内容在设备可视窗口的填充方式。有两种填充方式:
cover: 网页内容完全覆盖可视窗口
contain: 可视窗口完全包含网页内容

我们做安全区的适配前,需要把我们的viewport-fit设置成cover之后,再去做padding的适配。

也就是说需要把整个网页内容撑满,在撑满的基础上再去设置上下左右的间距,这样就一步一步比较严谨的做好了我们的安全区适配。

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">

12、北京智慧星光

  • 路由守卫
  • Vuex中mutations和actions的区别
  • 路由跳转报错怎么捕获
  • 路由跳转和传参数params和query,此时刷新网页,哪个数据会丢失
  • 数据处理
  • 前端分页怎么做
  • 登录鉴权流程,token存在哪儿
  • localStorage和sessionStorage、Cookie的区别和联系
  • UI库有没有用过一些联动的组件
  • v-for和v-if的优先级?怎么解决数据重复处理问题

1、Vue路由守卫

Vue路由守卫

1、全局守卫
vue-router全局有三个守卫:

  • router.beforeEach 全局前置守卫 进入路由之前
  • router.beforeResolve 全局解析守卫
  • router.afterEach 全局后置守卫 进入路由之后
// main.js 入口文件
import router from './router'; // 引入路由
router.beforeEach((to, from, next) => { next();
});
router.beforeResolve((to, from, next) => {next();
});
router.afterEach((to, from) => {console.log('afterEach 全局后置钩子');
});

to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。

next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。

2、路由组件内的守卫:

  • beforeRouteEnter 进入路由前
  • beforeRouteUpdate (2.2) 路由复用同一个组件时
  • beforeRouteLeave 离开当前路由时
  beforeRouteEnter (to, from, next) {// 在路由独享守卫后调用 不!能!获取组件实例 `this`,组件实例还没被创建},beforeRouteUpdate (to, from, next) {// 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 `this`// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。},beforeRouteLeave (to, from, next) {// 导航离开该组件的对应路由时调用,可以访问组件实例 `this`}

3、路由独享守卫
如果你不想全局配置守卫的话,你可以为某些路由单独配置守卫:

const router = new VueRouter({routes: [{path: '/foo',component: Foo,beforeEnter: (to, from, next) => { // 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖// ...}}]})

4、路由钩子函数的错误捕获
如果我们在全局守卫/路由独享守卫/组件路由守卫的钩子函数中有错误,可以这样捕获:

router.onError(callback => { // 2.4.0新增 并不常用,了解一下就可以了 console.log(callback, 'callback');
});

2、路由传参数

路由传参数有三种方式

  • 在路由的path里面写参数
  • query传参数
  • params传参数

在路由的path里面写参数

this.$router.push({path:`/home/${id}`,
})// 路由配置
{path:"/home/:id",name:"Home",component:Home
}
在Home组件中获取参数值
this.$route.params.id

params传参数

通过name来匹配路由,通过param来传递参数
this.$router.push({name:'Home',params:{id:id}
})
用params传递参数,不使用:/id
{path:'/home',name:Home,component:Home
}
Home组件中获取参数
this.$route.params.id

query传参数

this.$router.push({path:'/home',query:{id:id}
})
路由配置
{path:'/home',name:Home,component:Home
}
获取参数的方法
this.$route.query.id

params传参,必须使用命名路由的方式传参;
params传参,不会显示在地址栏上,会保存在内存中,刷新会丢失,可以配合本地存储进行使用;
query的参数会显示在地址栏上,不会丢失;

3、前端分页实现

computed: {// 计算属性对数据进行处理frontEndPageChange() {let start = (currentPage - 1) * pageSize;if (start >= thistableData.length) start = 0;let end = currentPage * pageSize;if (end >= thistableData.length) end = thistableData.length;return thistableDataslice(start, end);}
}

4、前端登录鉴权逻辑

前端登录鉴权逻辑

5、v-for和v-if的优先级

1.v-for的优先级高于v-if
原因:v-for比v-if优先级高,所以使用的话,每次v-for都会执行v-if,造成不必要的计算,影响性能,尤其是当前需要渲染很小一部分的时候。

<ul><li v-for="user in users" v-if="user.isActive" :key="user.id">{{ user.name }}</li></ul>

如上情况,即使有很多user 但是只要有一个需要使用v-if,也需要循环整个数组,这在性能上是极大的浪费。

但是我们可以使用computed计算属性解决:

<div><div v-for="(user,index) in activeUsers" :key="user.index" >{{ user.name }} </div>
</div>
data () {  // 业务逻辑里面定义的数据return {users,: [{name: '111111',isShow: true}, {name: '22222',isShow: false}]}}
computed: {activeUsers: function () {return this.users.filter(function (user) {return user.isShow;//返回isShow=true的项,添加到activeUsers数组})}
}

13、拼多多

  1. 说说小程序登录鉴权的逻辑,如果用sso同时共享小程序和H5的登录态
  2. 小程序微信支付的流程
  3. 小程序如何控制安全性(前端安全)
  4. Proxy拦截数组push,拦截对象改变
  5. Promise输出
  6. 让每行只放三个块元素,然后多余的换行处理
  7. H5和小程序适配
  8. webpack常用的plugin,有没有手写过loader、plugin

14、领岳科技

  1. 元素隐藏的几种方式
  2. 三栏布局以及水平垂直居中的方式
  3. Vue文件中的template中为什么有且仅有一个根容器
  4. webpack的loader和plugin有什么区别
  5. 有哪些常见的loader和plugin
  6. H5如何与native进行交互
  7. 斐波那契数列第n项
  8. 最长不重复子串
  9. 给出先序遍历和中序遍历还原二叉树
  10. this指向输出题
  11. async,await异步输出题

1、this指向的输出题

// 1:全局环境下this默认指向windowconsole.log(this) // window// 2:函数独立调用,函数中的this也默认指向windowfunction getThis () {console.log(this) // window}getThis()//3:被嵌套的函数独立调用的时候,this默认指向了windowlet obj1 = {a: 2,foo: function () {console.log(this) // obj1function test () {console.log(this) // window}test()},foo2: () => {console.log(this) // window},// 闭包函数中的this默认指向windowfoo3: function () {return function () {console.log(this) // window}},foo4: function () {return () => {console.log(this) // obj1}}}obj1.foo()obj1.foo2()obj1.foo3()()obj1.foo4()()// 4:IIFE自执行函数内的this默认指向windowlet a = 10function myFoo ()  {(function test(){console.log(this) // window})()}let obj2 = {a: 2,foo: myFoo}obj2.foo()
let obj1 = {name: 'obj1',fun1: function () {console.log(this.name)},fun2: () => {console.log(this.name)},fun3: function () {return function () {console.log(this.name)}},fun4: function () {return () => {console.log(this.name)}}
}
let obj2 = {name: '2323232'
}
obj1.fun1() // obj1
obj1.fun2() // undefine
obj1.fun3()() // undefine
obj1.fun4()() // obj1
console.log('--------------------------------------')
obj1.fun1.call(obj2) // 2323232
obj1.fun2.call(obj2) // undefine
obj1.fun3().call(obj2) // 2323232
obj1.fun4().call(obj2) // obj1

2、异步输出顺序问题

async、await会阻塞其后面内容的输出
promise不会阻塞其后面内容的输出


async function test1 () {console.log('1111111111')const res = await test2()console.log('res', res)console.log('22222222222')
}async function test2 () {console.log('test2')
}console.log('scri1')
setTimeout(() =>{console.log('123')
}, 1000)
test1()
new Promise((resolve, reject) => {console.log('before Promise')resolve('promise')console.log('after Promise')
}).then(res => {console.log(res)
})
console.log('scri2')

15、百度

  • 深拷贝和浅拷贝的方式
  • 说说Vue父子组件通信
  • 父子组件执行顺序父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
  • Commonjs和es6的modules区别
    前端模块化
  • webpack的hash参数的三种取值方式
  • 浏览器重绘重排以及触发的方式
  • 强缓存和协商缓存的状态码
  • 根据id和pid构造出树形结,手写代码

1、浏览器重绘重排

重排:
当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。

回流就好比向河里(文档流)扔了一块石头(dom变化),激起涟漪,然后引起周边水流受到波及,所以叫做回流

引起浏览器重排的方法:

  1. 添加或者删除可见的DOM元素
  2. 元素的尺寸、大小改变
  3. 内容变化,比如在input框中输入内容
  4. 浏览器窗口大小发生改变resize
  5. 计算 offsetWidth 和 offsetHeight 属性
  6. 设置style属性的值

重绘:

2、深拷贝和浅拷贝以及其实现方式

深浅拷贝
js的数据类型主要有基本数据类型引用数据类型两种
基本数据类:
String、Number、Boolean、Null、Undefined、Symbol
引用数据类型:
Object(Object、Array、Function)
javascript的变量的存储方式–栈(stack)和堆(heap)
栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的值和引用类型的地址

堆:动态分配的内存,大小不定,也不会自动释放。里面存放引用类型的值。

浅拷贝—浅拷贝是指复制对象的时候,只对第一层键值对进行独立的复制,如果对象内还有对象,则只能复制嵌套对象的地址深拷贝—深拷贝是指复制对象的时候完全的拷贝一份对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。其实只要递归下去,把那些属性的值仍然是对象的再次进入对象内部一 一进行复制即可。

let a  = 1
let b = a
a = 2
console.log(b) // 1let obj1 = {a: 123,b: {dataB: 'kell'}
}
let obj2 = obj1
obj1.a = 456
console.log(obj2.a) // 456let obj3 = {a: 123,b: {dataB: 'kell',olo: {po: 'okoko'}}
}
let obj4 = Object.assign({}, obj3)
obj3.a = 90
console.log(obj4.a) // 123
obj3.b.dataB = 'koko'
console.log(obj4.b.dataB) // kokolet obj5 = {...obj3}
console.log(obj5) // { a: 90, b: { dataB: 'koko', olo: { po: 'okoko' } } }

对象浅拷贝的方式:

  1. let obj4 = Object.assign({}, obj3)Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
  2. 拓展运算符 let obj5 = {...obj3}

数组的浅拷贝方式:

  1. arr.concat()
  2. arr.slice()
let arr = ['one', 'two', 'three'];
let newArr = arr.concat();
let newArr = arr.slice();

正则匹配所有域名及其子域名

const regStr = /^([a-zA-Z\d-_\*@]+\.)*baidu\.com$/
let str = 'wenku.baidu.com'
let str2 = 'baidu.com'
console.log(regStr.test(str))
console.log(regStr.test(str2))

3、根据id和pid构造出树形结构

比如:

const arr = [{id: 0,pid: -1
}, {id: 1,pid: 0
}, {id: 2,pid: 0
}, {id: 3,pid: 1
}, {id: 4,pid: 2
}];

经过处理后转化成:

[{id: 0, pid: -1, children: [{id: 1,pid: 0,children: [{id: 3,pid: 1,children: []}]}, {id: 2,pid: 0,children: [{id: 4,pid: 2}]}]
}]

处理的方法如下:

function toTree(data) {let result = []if (!Array.isArray(data)) {return result}data.forEach(item => {delete item.children;});let map = {};data.forEach(item => {map[item.id] = item;});console.log(map)data.forEach(item => {let parent = map[item.pid];console.log('parent', parent)if (parent) {(parent.children || (parent.children = [])).push(item);} else {result.push(item);}});console.log(result)return result;
}
toTree(arr)

16、米可世界

  1. CORS解决跨域
  2. 跨域的请求到底有没有发出去(分复杂和简单跨域,复杂跨域首先会发送option预检请求)
  3. webpack的hash、chunkHash、contentHash
  4. 有没有自己定义过Plugin和Loader
  5. 箭头函数的this指向,箭头函数的this是在定义时候就确定了,且无论怎样都不会改变
  6. H5的触底加载,怎么实现
  7. webpack的文件监听
  8. Vue3有了解过吗?
  9. async、await除了用try、catch还可以用啥进行包裹

17、优贝在线(音乐、K歌、社交APP)

  • CSS有哪些可继承的属性
  • 移动端适配
  • 怎么判断触底加载下一页
  • 防抖和节流区别及其联系
  • ajax发请求,fetch发请求、axios发请求(怎么拦截)
  • 解决跨域的方案。CORS需要设置哪些字段
  • 正则表达式

1、CSS有哪些可继承属性

CSS的可继承属性

  • 字体系列属性:font、font-size、font-family、font-style、font-variant、font-stretch、font-size-adjust
  • 文本系列属性: text-algin、text-indent、line-height、word-spacing、letter-spacing、text-transform、color、direction
  • 可见属性:visibility
  • 光标属性:cursor

2、正则表达式

正则表达式

面经--------------相关推荐

  1. 【面经——《速腾聚创科技有限公司——深度学习算法工程师》】

    自我介绍 实习项目 1)项目主要应用的领域? 2)难点在哪?--机械臂吸盘大小和目标大小之间坐标的协调 3)难点不在于算法,在于数据的处理和均衡性?对于数据均衡方面有什么理解(方法) 答:图像变换-- ...

  2. 上海合合信息科技有限公司--深度学习算法实习生--面试题整理

    机器学习 一个机器学习模型包含哪几个部件,谈谈您对每个部件的理解 特征提取部件:提取特征 损失函数部件:引导模型的优化方向 优化器部件:模型的优化,参数更新方法 评价指标:对模型性能的评估 softm ...

  3. 听说深度学习算法工程师均资已达22K+了! 你还在犹豫要不要跳槽?

    文  章  目  录 1 热门.稀缺高端岗位薪资 2 人工智能职位发展趋势分析 3 人工智能职位就业指导 薪酬-北上深平均月薪18K+ 薪酬地图:从职位薪水来看,人工智能行业的高薪主要分布在京津.长三 ...

  4. 【杂谈】什么是我心目中深度学习算法工程师的标准

    有三AI平台只专心做原创输出很少扯淡也不蹭热点,不过最近询问的朋友多了,不得不统一写篇文章来回答一下这个大家都很关心的问题,当然,这仅仅是个人观点. 作者&编辑 | 言有三 目前利用深度学习这 ...

  5. 岗位推荐 | 百度招聘计算机视觉、深度学习算法工程师(可实习)

    PaperWeekly 致力于推荐最棒的工作机会,精准地为其找到最佳求职者,做连接优质企业和优质人才的桥梁. 如果你需要我们来帮助你推广实习机会或全职岗位,请添加微信号「pwbot02」. 工作地点: ...

  6. 刚发布!开发者调查报告:机器学习/深度学习算法工程师急缺

    近日,CSDN发布了<2019-2020中国开发者调查报告>,本报告从2004年开始针对一年一度的CSDN开发者大调查数据分析结果形成,是迄今为止覆盖国内各类开发者人群数量最多.辐射地域. ...

  7. 「杂谈」什么是我心目中深度学习算法工程师的标准

    http://blog.sina.com.cn/s/blog_cfa68e330102zoco.html 有三AI平台只专心做原创输出很少扯淡也不蹭热点,不过最近询问的朋友多了,不得不统一写篇文章来回 ...

  8. 深度学习算法工程师面试知识点总结(四)

    这是算法工程师面试知识点总结的第四篇,有兴趣的朋友可以看看前三篇的内容: 深度学习算法工程师面试知识点总结(一) 深度学习算法工程师面试知识点总结(二) 深度学习算法工程师面试知识点总结(三) 基于t ...

  9. 深度学习算法工程师面试知识点总结(一)

    深度学习算法工程师岗位需要具有的技术栈初步总结如下: 这个总结并不是很完整,这个方向所需要的知识体系非常的庞大,例如高等数学基础.线性代数.概率论的基础,这对很多的同学来说是一个比较大的挑战.还需要针 ...

  10. 推荐 | 一个统计硕士的深度学习算法工程师的成长之路

    公众号推荐 推荐人/文文 俗话说,一个人走得快,但一群人可以走的远.在数据科学和机器学习的道路上,相信每个人都不是闭门造车的人.技术学习除了在个人努力外,交流和分享也是很重要的一部分. 今天给大家推荐 ...

最新文章

  1. 使用OpenCV,Python和dlib进行眨眼检测及计数
  2. 与smart_Smart超纯水系统及原理
  3. Win7最高权限问题
  4. poi excel mysql_java的poi技术读取Excel数据到MySQL
  5. C#:把dll封入exe中方法
  6. JS点击获取验证码后60秒内禁止重新获取(防刷新)
  7. 区块链产业生态、存在问题及政策建议|一文读懂新趋势
  8. oracle怎么存视频地址,oracle的警告文件存储方式和地址
  9. OpenGL二维纹理映射(2D textures)
  10. 大众点评信息流基于文本生成的创意优化实践
  11. css 图片剪切object-fit属性
  12. C++17尝鲜:fold expression(折叠表达式)
  13. 自动收取蚂蚁森林能量雨
  14. 想当然的性能调优:加一个SSD
  15. python turtle画猫_Turtle库画小猫咪
  16. SQL server数据库安装包下载
  17. 通过电气化来减少排放量 - 白皮书
  18. 计算机是如何工作的 计算机原理
  19. latex怎么给图片命名_[Latex] Beamer 入门
  20. 屏蔽百度及其广告的部分Host

热门文章

  1. OpenShift免费空间申请教程
  2. 国产动漫屡遭吐槽 融资困境待解
  3. ABB工业机器人功能函数之空间距离计算
  4. 数据库系统设计课程总结3-sql 进阶
  5. MAX3232使用全部2路串口互相干扰的问题
  6. PyQt5下界面设计, 无边框加阴影界面, 鼠标左键移动事件
  7. OSS-操作支持系统
  8. SpringCloud 面试谈资 软实力
  9. 实习技术员的基本功(五)
  10. 最新计算机科学学术期刊影响因子排名