字节跳动前端面经(二面)
面试的抖音电商前端岗位,已拿offer。
岗位薪资还不错,福利也多,需要内推的同学可以私信我!!
接上篇字节跳动前端面经(一面) ,这次是二面内容
1. 讲一下浏览器缓存,什么时候使用本地缓存,什么时候使用协商缓存,什么时候不使用缓存
接口不使用缓存,只有静态资源,图片、css、js等使用缓存。缓存规则分为http1.0版本和http1.1版本
http1.0
- 强缓存,expires,有效时间内获取本地缓存。若无强缓存活强缓存超过有效期,使用协商缓存。
- 协商缓存,Last-Modified 响应头,If-Modified-Since 请求头,该值就是服务器端上一次响应资源中的Last-Modified字段值。当服务端返回304,没过期,使用本地资源。服务端返回200、新的Last-Modified和最新资源,表示资源已过期,使用最新资源。
http1.1
- Cache-Control
- no-store 永远不缓存
- no-cache 协商缓存,询问服务器是否可用本地缓存,配合Last-Modified或者Etag
- max-age 强缓存 覆盖http1.0的Expires
- Etag/If-None-Match,覆盖http1.0的Last-Modified/If-Modified-Since
- Etag 响应头 服务器资源哈希值
- If-None-Match 请求头 If-None-Match字段的值就是服务器端上一次响应资源中的Etag字段值;max-age或者expires过期了才使用,服务端返回304,没过期,使用本地资源。服务端返回200、新的Etag和最新资源,表示资源已过期,使用最新资源。
若请求头,响应头中http1.0和http1.1表示缓存的字段都存在,测后者覆盖前者
2. 用vue写一个dialog组件,用如下方式调用
<v-dialog header="标题标题" text="内容内容" v-model="dialogShow" v-on:confirm="confirm"/>
面试的时候不需要写样式,实现逻辑就行,关键逻辑点
- v-model控制弹窗组件的显示隐藏
- props传参弹窗组件的标题和内容
- $emit触发点击确定和取消的事件
组件实现
<template> <div> <div v-show="dialogShow"></div> <div v-show="dialogShow"> <div >{{ header }}</div> <div >{{ text }}</div> <div > <div v-on:click="confirm">确定</div> <div v-on:click="cancel">取消</div> </div> </div> </div> </template> <script> export default { name: 'Dialog', model: { prop: 'dialogShow', event: 'changeShow' }, props: { dialogShow: { type: Boolean, default: false }, header: { type: String, default: '信息' }, text: { type: String, required: true } }, methods: { confirm () { this.$emit('changeShow', false) this.$emit('confirm') }, cancel () { this.$emit('changeShow', false) this.$emit('cancel') } } } </script>
3. 微前端css隔离怎么做
因为简历里写了微前端,这里就被问到了,因为只用过webpack5、没用过乾坤,面试时只回答了下面第一种情况
目前市面上的微前端框架大致分为两种
- 基于webpack5,微组件的框架,运行时通过http请求获取组件,动态加载
- 基于乾坤,根据不同路由加载不同子应用的方式
以下分别说明
- 如果使用webpack5那种主应用加载微组件方式,且都是vue项目,不会有任何css冲突问题。vue-loader会给每个class改名,生产环境下为全路径加class名的hash值,不可能冲突
- 如果使用乾坤的微前端,大致上有3中css隔离方式
- shadow dom,严格隔离,会有坑。例如弹窗默认添加到document.body下,不在shadow dom中,失去样式。
- 工程化手段,css module。
- 主应用改写子应用css,例如主应用给子应用A分配的div id为aaa,那么所有A应用的css都添加 #aaa。
4. v-model原理
v-model就是双向绑定,是v-bind:value和v-on:input的语法糖
<input v-model="val"> <input v-bind:value="val" v-on:input="val = $event.target.value">
第一向,改变数据时通知视图更新v-bind:value="val"
。这一步也就是vue响应式的原理。
- vue遍历data中所有的属性,挂在this下,使用Object.defineProperty给每一个属性都注册getter,setter。
- get用来收集依赖,set用来执行notify,发布更新事件。
- 每个属性创建一个Dep对象,作为订阅发布模式的中间机构来收集依赖
- mount阶段的updateComponent会new Watcher(),每一个Watcher对应一个vue component,调用组件的render函数。
- 若没有render函数,会执行模板编译过程,生成render函数。render函数执行时,会访问定义在模板里的各属性,会触发之前定义的get,收集依赖,将当前的Watcher注册到dep当中,dep.depend()。
- 模板里没写this是因为渲染函数外面套了一层with(this){//....}
- 当data中属性变化时,触发set方法,执行dep.notify(),通知所有的Watcher调用update函数更新
- update添加进队列,在下一个promise.then中执行队列中的更新任务
- 再经过dom diff,渲染页面
第二向,视图改变时通知数据更新v-on:input="val = $event.target.value"
。
- 通过监听表单元素的input事件,从而通知数据更新。
5. 对象将key转大写字母换成_小写
const address = [ { addressId: 1, addressName: '北京市', subDistrict: [ { addressId: 11, addressName: '海淀区', subDistrict: [ { addressId: 111, addressName: '中关村', }, ], }, { addressId: 12, addressName: '朝阳区', }, ], }, { addressId: 2, addressName: '河北省', }, ];
这题就是考察递归和大小写转换,比较简单
function convert(arr) { let newArr = []; for (let i = 0; i < arr.length; i++) { let obj = arr[i]; let newObj = {}; for (const key in obj) { const newKey = key.replace(/([A-Z])/g, '_$1').toLowerCase(); if (Array.isArray(obj[key])) { newObj[newKey] = convert(obj[key]); } else { newObj[newKey] = obj[key]; } } newArr.push(newObj); } return newArr; }#字节跳动##面经#