前言
今年的前端行情着实不太好。在面试太少的情况下,把握住每次面试机会,记录一下每次的面试题经历
4月初开始 投简历俩月了一共12个面试,去年疫情期间面试,半个月8个面试。欲哭无泪!!!
卷 + 少hc + 要求高 = [0] Offer
面试题如下
多个公司的面试题融合,不分公司!!!
问题:移动端是如何做适配的
答案:
- rem(根据根节点定义font-size) + viewport缩放【淘宝方案】
- 第三方插件+配置
- flex弹性布局
- 媒体查询 css3 的 @madia queries
问题:使用promise实现并发请求限制N个
答案:
(每次执行三个,一个执行完再补上一个,一直保持三个promise在执行)
- 答案关键点:
- promise.race()
- 新建一个栈[]、长度
- promise.allSettled()
- promise.resolve().then()
var urls = [
"https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg",
"https://www.kkkk1000.com/images/getImgData/gray.gif",
"https://www.kkkk1000.com/images/getImgData/Particle.gif",
"https://www.kkkk1000.com/images/getImgData/arithmetic.png",
"https://www.kkkk1000.com/images/getImgData/arithmetic2.gif",
"https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg",
"https://www.kkkk1000.com/images/getImgData/arithmetic.gif",
"https://www.kkkk1000.com/images/wxQrCode2.png",
];
function loadImg(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = function () {
resolve(url);
};
img.onerror = reject;
img.src = url;
});
}
async function limitLoad(urls, handler, limit) {
const promises = [];
const queue = urls.splice(0, limit).map((url, index) => {
const _p = handler(url);
promises.push(_p);
return _p.then((res) => {
return [index, res];
});
});
for (const item of urls) {
const [index] = await Promise.race(queue);
const _p = handler(item);
promises.push(_p);
queue[index] = _p.then((res) => {
return [index, res];
});
}
return Promise.allSettled(promises);
}
limitLoad(urls, loadImg, 3).then((res) => console.log(res));
问题:虚拟列表描述
答案:
按需显示的一种实现,只对可见区域进行渲染。 对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能
-
答案关键点:
- 可视区域高度
- item高度
- list高度
- 当前滚动位置
- 偏移量(startOffset)
- 可显示item个数
-
定高
- 计算当前可见区域起始数据的 startIndex
Math.floor(scrollTop / itemSize)
- 计算当前可见区域结束数据的 endIndex
endIndex = startIndex + visibleCount
- 计算当前可见区域的数据,并渲染到页面中
Math.ceil(screenHeight / itemSize)
- 计算startIndex对应的数据在整个列表中的偏移位置startOffset并设置到列表上
startOffset = scrollTop - (scrollTop % itemSize);
- 计算当前可见区域起始数据的 startIndex
export default {
name:'VirtualList',
props: {
//所有列表数据
listData:{
type:Array,
default:()=>[]
},
//每项高度
itemSize: {
type: Number,
default:200
}
},
computed:{
//列表总高度
listHeight(){
return this.listData.length * this.itemSize;
},
//可显示的列表项数
visibleCount(){
return Math.ceil(this.screenHeight / this.itemSize)
},
//偏移量对应的style
getTransform(){
return `translate3d(0,${this.startOffset}px,0)`;
},
//获取真实显示列表数据
visibleData(){
return this.listData.slice(this.start, Math.min(this.end,this.listData.length));
}
},
mounted() {
this.screenHeight = this.$el.clientHeight;
this.start = 0;
this.end = this.start + this.visibleCount;
},
data() {
return {
//可视区域高度
screenHeight:0,
//偏移量
startOffset:0,
//起始索引
start:0,
//结束索引
end:null,
};
},
methods: {
scrollEvent() {
//当前滚动位置
let scrollTop = this.$refs.list.scrollTop;
//此时的开始索引
this.start = Math.floor(scrollTop / this.itemSize);
//此时的结束索引
this.end = this.start + this.visibleCount;
//此时的偏移量
this.startOffset = scrollTop - (scrollTop % this.itemSize);
}
}
};
-
非定高
追问:那懒加载呢?是什么原理
答案:
图片先用占位符表示,不要将图片地址放到src属性中,而是放到其它属性(data-original)中 页面加载完成后,监听窗口滚动,当图片出现在视窗中时再给它赋予真实的图片地址,也就是将data-original中的属性拿出来放到src属性中 在滚动页面的过程中,通过给scroll事件绑定lazyload函数,不断的加载出需要的图片
- 答案关键点:
- data-src
- src默认图片占位符
- 监听窗口滚动
问题: BFC
答案:
块级格式化上下文,是css的一个布局的统称,独立的渲染区域。让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
-
触发条件:
- 根元素
- float不为none
- overflow不为visible
- display的值为inline-block、inline-flex、flex、flow-root、table-caption、table-cell。
- position的值为absolute或者fixed
-
作用:
- 开启bfc不会被浮动元素覆盖
- 开启bfc的元素子元素和父元素不会重叠
- 开启bfc的元素高度不会塌陷
- 取消margin的重叠
问题:解释闭包
答案:
(真的被这个问题问到怀疑人生!!!)
父函数被销毁的情况下,返回的子函数的[[scope]]中仍然保留着腹肌的单变量对象和作用域链,因此可以继续访问到父级的变量对象
-
解决了什么问题
- 维持变量,不被垃圾回收
- 实现变量、方法私有化
-
用途
- 可以读取函数内部的变量
- 让这些变量的值一直保持在内存中
-
闭包产生的内存泄露怎么办
- 退出函数前,将不使用的局部变量赋值为null
- 避免变量的循环赋值和引用
问题:数组有多少个遍历方法,性能比较
答案:
- for : 频率最高,性能中等 但仍有优化空间
- 优化的for : 提取变量放在第一个参数里
- forEach : 频率较高,性能比for弱
- for in : 效率最低 性能最差
- map : 代码优雅,但效率低,比forEach还差
- forof : 性能比forin好,比for循环差
- while : 效率较好
追问:map foreach
-
相同点:
- 循环遍历每一项,
- 每次遍历都有三个参数,
- 匿名函数中this都是指window,
- 都可以在cb中改变原数组
-
不同点:
-
map:
-
- 有返回值,可以return出一个length和原数组一样的数组;
-
- 会分配内存空间存储新数组并返回
-
-
foreach:
-
- 没有返回值,是undefined;
-
- return不会终结遍历,除了异常不能终止 3. 不会分配空间
-
-
追问:forof forin
-
for in 用它可以遍历数组,对象,集合。遍历数组遍历的值是数组index索引,遍历对象和集合时遍历的是key值。
- 遍历顺序有可能不是按照实际数组的内部顺序
- 会遍历数组所有的可枚举属性,包括原型。最好不要遍历数组
-
for of 是es6 新加入的语法,适用于遍历数组,字符串,map/set等拥有iterator迭代器的的集合。
- 不能直接遍历对象,会报错。因为Object对象中没有内置的迭代器iterator