文章目录
- 前言
-
- [1. Flex 布局缩写](#1. Flex 布局缩写)
- [2.CSS 居中方案](#2.CSS 居中方案)
- [3.v-if 与 v-show 的真实性能差异](#3.v-if 与 v-show 的真实性能差异)
- [4.nextTick 到底在等什么](#4.nextTick 到底在等什么)
- [5.循环中的 Key](#5.循环中的 Key)
- 6.跨域问题 (CORS)
- [7.map 和 forEach 的本质区别](#7.map 和 forEach 的本质区别)
- 8.promise.all
- 9.数组排序陷阱
- 10.箭头函数坑
前言
大家好,今天是冲击中级工程师第二天,让我们来完成今天的面试题打卡。
1. Flex 布局缩写
题目:我们经常写 flex: 1,请问它其实是哪三个属性的缩写?默认值分别是多少?
css
.item {
flex: 1;
}
解释:
flex: 1 是 flex-grow、flex-shrink、flex-basis 这三个属性的缩写。
flex-grow: 1 (如果有剩余空间,我放大)
flex-shrink: 1 (如果有空间不足,我缩小)
flex-basis: 0% (我的初始大小忽略不计,优先占满剩余)
避坑:如果不写 flex: 1,默认值其实是 0 1 auto(不放大,会缩小,看内容大小)。
重点是flex-basis,它决定了按比例分配,而不是内容大小
2.CSS 居中方案
题目:未知宽高的元素如何水平垂直居中?为什么现在推荐用 transform 而不是 margin-top: -50%?
css
.center {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
解释:常规下还有flex居中,这里讲解绝对定位的居中,
margin-top 的百分比是相对于父元素宽度的(这是一个反直觉的坑),很难精准居中。
transform: translate 的百分比是相对于元素自身宽度的。
3.v-if 与 v-show 的真实性能差异
题目:什么时候用 v-if,什么时候用 v-show?如果我要做一个频繁切换的 Tab 标签页,选哪个?
答案:使用v-show,v-if是真实"条件渲染",他会销毁和重建内部事件监听器和组件(触发生命周期),初始化开销小,切换开销大;v-show只是改变了css的display属性(block和none切换),组件一直在dom中,初始化开销大,切换开销小。
4.nextTick 到底在等什么
题目:修改了数据,想拿到 DOM 最新的高度,直接获取拿不到,为什么要包一层 nextTick?
答案:vue的更新是异步的,当修改message.value = 'new'时,vue并没有去直接更新dom,而是开启一个队列,把这个修改记下来。等待同一事件结束后,再统一更新dom,所以这时有可能拿不到最新的结果。nextTick就是在说:等事件结束,dom刷新后再执行我的回调。
5.循环中的 Key
题目:v-for 循环列表时,为什么不能用 index(数组下标)作为 key?
答案:当发生插入,删除,逆序操作时,会出现下面的后果:1.如果你用 index 做 key,数据的 index 变了,但 key 没变(还是 0, 1, 2...)。
2.Vue 的 Diff 算法会认为"这个组件没变",于是它会复用之前的 DOM 节点,只更新里面的文字。
3.如果列表里有 Input 输入框,你会发现删除了第二项,结果第三项的数据跑到了第二项的输入框里,产生严重的 Bug。
6.跨域问题 (CORS)
题目:前端发请求报 CORS 错误,作为前端工程师,除了让后端加 Header,你本地开发怎么解决?
答案:使用前端代理跨域是浏览器的安全限制,服务器与服务器之间通信是没有跨域限制的。 在 Vue/React 项目配置 devServer.proxy,其实就是启动了一个 Node 中间层。你的浏览器发给本地 Node,本地 Node 转发给后端,巧妙绕过了浏览器的同源策略。
7.map 和 forEach 的本质区别
题目: 都能遍历数组,它们最大的区别是什么?能用 break 跳出 forEach 吗?
答案:返回值:map 返回一个新数组(适合数据格式转换);forEach 返回 undefined(适合单纯执行副作用)。都不能用 break 或 continue 跳出循环。只能用 try/catch 抛出异常强行停止,或者改用普通的 for...of 循环。
8.promise.all
问题:Promise.all([p1, p2, p3]),如果 p2 报错了,p1 和 p3 的结果还能拿到吗?怎么解决?
答案:如果不处理,确实会直接崩盘。 解决技巧:在传入 all 之前,给每个 Promise 接一个 .catch()"兜底"。代码示例如下:
js
// 即使出错,也返回一个带有 status 的对象,保证 all 能走完
Promise.all([
p1.catch(e => ({ status: 'fail', err: e })),
p2.catch(e => ({ status: 'fail', err: e }))
]).then(results => {
// 这里可以过滤出成功的和失败的
})
还有就是使用Promise.allSettled()
9.数组排序陷阱
题目:下面代码输出什么?
javascript
const arr = [1, 10, 2, 21];
arr.sort();
console.log(arr);
输出:[ 1, 10, 2, 21 ]
解释:sort() 如果不传比较函数,默认会将数字转换成字符串,然后按照字符编码(Unicode)顺序排序。 因为字符串 "10" 的第一个字符 "1" 比 "2" 小,所以 "10" 排在 "2" 前面。 修正:arr.sort((a, b) => a - b)
10.箭头函数坑
题目:下面代码输出什么?
javascript
const getObj = () => { a: 1 };
console.log(getObj());
输出:undefined
解释:大括号 {} 在箭头函数里,默认被认为是代码块(Function Body),而不是对象字面量。代码块里写 a: 1 只是一个标签语法(Label),并没有 return 任何东西。 修正:用圆括号包起来 const getObj = () => ({ a: 1 });
#总结
今天面试题就到这里,让我们每天学习几个题,一起成长。管他难易,获得成长就好。明天见。