某公司面视经验
声明
本文章仅作为我的笔记,不作为参考。
面后感
本次面视带给我的感觉就是:自我能力还需要提升。对于面视官所说的背景还可以
,我认为我的背景是不够的,也是不够自信。因为我仅仅是个三本的本科大学生,在前端领域也没有深造,仅仅是因为我在学校的工作中更多的是前端开发。实验室里前端开发在我这一届也比较少,给了我种错觉:我已经会的足够多了。
然而结果可想而知~
一大早六点就起来前往公司所在城市去面视。早到了还有点不知所措,通过BOSS联系HR之后才进去的大楼。进去后在前台拿到了前端面试题以及信息表。让我重现当时的题目吧。
笔试题
题目可能有点乱或少。等我想起来再补充吧。先复习。
1. JS的数据类型有哪些?
undefind, null, boolean, string, symbol, number, bigint。
我当时答了什么呢?
我当时答了undefind, string, number, object, set, map, symbol
。
脑子里只有七种,没有知识体系支撑着我的面视,最终的结果是答出了非常离谱的答案。
object, set, map都是引用数据类型才对。包括Function,Array都是引用数据类型。
第一题就答得非常离谱了。
2. 前端有哪几种存储方式?
cookie: 储存再用户本地终端的数据
web storage API: {
localStorage: 用于长久保存网站的数据,没有过期时间。(用户可删除)
sessionStorage: 用于临时保存同一窗口或标签页的数据,在关闭窗口或标签页后会删除。
}
indexedDB: 浏览器提供的本地数据库,可以用js脚本创建和操作。允许储存大量数据,提供查找接口,还能建立索引。
我回答:3种。
笑死,我脑子里只有数量,没有具体的东西。对数量敏感是吧。
3. 手写防抖节流。
// 防抖
//业务逻辑
function task(){
console.log(this.value);
}
function debounce(fn, delay){
var time = null;
return function(){
if(time != null){
clearTimeout(time)
}
time = setTimeout(() => {
task.call(this)
}, delay);
}
}
/*-------------------------------------------------------------------------------*/
//节流
//业务逻辑
function task(){
console.log('触发');
}
function throttle(fn,delay){
var flag = true;
var time = null;
return function(){
if(flag){
time = setTimeout(() => {
task.call(this)
flag = true;
}, delay)
}
flag = false;
}
}
我的答案:
// 防抖
let timer = null;
function debounce() {
if (timer !== null) {
return;
}
timer = setTimeout(() => {
// 业务逻辑
clearTimeout(timer);
}, 100);
}
// 节流
let timer = null;
function throttle() {
if (timer !== null) {
timer = setTimeout(() => {
// 业务逻辑
clearTimeout();
}, 100);
}
}
面试官说的我写的两个是一个意思,好像。。。确实不知道是当时太紧张了写得有问题还是如何,可能跟我的答案不太一样。然后问我防抖节流的定义。
我答:
防抖:单位时间内只执行一次。
节流:单位时间内只执行最后一次。
这么再回去一看,确实,应该是我的节流写的有问题。应该覆盖上一个节流事件。。。
4. 数组操作:pop、push、shift、unshift的区别?
这个很简单,没问题。
5. this指向以及作用域。
当时是给了这么一道题。
var name = 1;
const obj = {
name: 2,
objFunc: function() {
return function() {
return this.name;
}
}
}
console.log(obj.objFunc()());
问输出是什么?
我的理解是这是一个闭包,this的上下文环境应该是通过obj.objFunc()
调用后,当前的上下文环境是obj
,再调用一次后进入匿名函数,上下文环境在堆栈中应该是obj
?我理解了这应该是一个闭包?然后this.name
应该是2?
然而答错了。回来用vscode跑一次试试。
额…在nodejs环境中是undefine, 在浏览器环境中是1。为何?
问了师兄。噢~内部this的指向是全局。好嘛,还是上下文环境不熟悉。js运行不熟悉。
6. http状态码
1xx: 请求信息
表明这是一个临时性相应。此相应状态由状态行和可选的HTTP头组成,以一个空行结尾。HTTP /1.1以上
100 *请继续请求
101 请切换协议
102 将继续执行请求
2xx: 成功状态
表明请求成功。
200 *请求成功
201 *请求已被接受,等待资源响应。
202 *请求已被接受,但尚未处理。
203 请求已成功处理,结果来自第三方拷贝。
204 *请求已成功处理,但无返回内容。
205 请求已成功处理,但需重置内容。
206 请求已成功处理,但仅返回了部分内容。
207 请求已成功处理,返回了多个状态的XML消息。
208 请求已发送。
226 已完成相应。
3xx:重定向状态
表示客户端需要采取更进一步的行动来完成请求。通常用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。
300 *返回多条重定向供选择。
301 *永久重定向。
302 *临时重定向。
303 当前请求的资源在其他地址。
304 *请求资源与本地缓存相同,未修改。
305 必须通过代理访问。
306 (已废弃)请切换代理。
307 临时重定向,同302.
308 永久重定向,且禁止改变http方法。
4xx:客户端错误
表示客户端的请求存在错误,导致服务器无法处理。除非响应的是一个HEAD请求,否则服务器就应该返回一个解释当前错误状态的实体,以及这是临时的还是永久性的状况。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误相应中的实体内容。
400 *请求错误,通常是访问的域名未绑定引起。
401 *需要身份认证验证。
402 *暂无标准约定。
403 *禁止访问。
404 *请求的内容未找到或已删除。
405 *不允许的请求方法。
406 *无法响应,因资源无法满足客户端条件。
407 要求通过代理的身份认证。
408 请求超时。
409 存在冲突。
410 资源已经不存在(过去存在)
411 需要定义 Content-Length 头部字段
412 头部不满足服务器条件
413 请求实体大于服务器定义的限制。
414 URI过长(服务器不接受)
415 数据格式错误,拒绝请求
416 URI过长(服务器不支持)
429 限制请求速率
431 请求头字段太大。
451 请求不合法。
5xx:服务器端错误
500 *服务器错误
501 *服务器不支持该请求方法,请用GET和HEAD。
505 *HTTP版本错误
506 服务器内部配置错误。
508 请求时无限循环
510 *服务器需升级
511 需要身份认证
当然面试官没问那么多。只是自己还需要熟悉一下。
7. 宏任务以及微任务的执行流程(浏览器的执行流程)
先上笔试题
const p = () => new Promise((resolve, reject) => {
console.info(3);
const p1 = () => new Promise((resolve, reject) => {
console.info(2);
setTimeout(() => {
console.info(5)
resolve(7);
}, 0)
resolve(6);
});
resolve(1);
p1().then((res) => {
console.info(res);
});
});
console.info(4);
p().then((res) => {
console.info(res)
});
没准备充分就去面视是这样的,简单的宏任务微任务也没做出来。
正确答案应该是4 3 2 6 1 5
我当时答了啥?我答了4 3 1 2 6 5
对事件循环、宏任务微任务的执行了解到太少了。
正确应该是在一次事件循环中,先执行所有的宏任务、宏任务执行结束后,再开始执行本次事件循环中的所有的微任务。
应该最简单的例子应该就是这个了吧。
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.info(i);
}, 100);
}
输出五次5。
诶呀~这还敢跑去面试。
人事面
人事小姐姐是在BOSS上联系的。看过简历后马上就约线下面了,爽快得有点不知所措~但还是珍惜每一次的面视机会吧。
开始是自我介绍,然后讲讲自己的优势吧。面视经验少的我不知该说啥,我有优势的话估计就是在校项目做得多?但也都是些小项目。然后人事就让我拿这BOSS上的条例说说~emmm还行吧。
技术面
人事面完事就是技术面了。技术面是两位,一位leader一位面试官。
再来一次自我介绍,巴拉巴拉把自己做过的项目讲一大堆~
介绍完后就是八股拷打了吧!让我回忆回忆~
能记起来多少是多少吧~
- es6新特性有哪些
我只是在回答名字,什么set map proxy async await symbol…
想逐个展开,但是脑子已经不支持我展开了。明明才看过书了解Symbol的特性、proxy的特性来着…
麻了。 - vue2 vue3
咋个说…我只会封装组件…用组件…生命周期钩子我还得看着图才能讲…废
倒是刚开始翻开《vue2深入浅出》,知道了vue2的数据监测用的defineProperty做的,然后用proxy重构。额…真就只会用喽。 - webpack工作原理
应该写了解webpack配置的。笑死。
面试官说,当编译less的时候,浏览器是不认识less文件的,需要webpack翻译成浏览器认识的css文件。这懂哪。我以为要回答的是比如如何将js模块化、如何将静态文件分类打包…然后就说不懂…汗流浃背了。感情我是来上课的
相信如果真有人看的话,看到这已经看不下去了吧哈哈哈哈我有多菜。 - 深拷贝浅拷贝
啊 这也是面试题的一个,我写的啥
emmm好好好,可以是可以。面试官说有弊端,比如当数据类型是obj1 = JSON.parse(JSON.stringify(obj2));
Date
这种的时候,可能会丢失类型,有没有其他的方法。嗯!有很多来着。但是脑子里想不出来了。只记得有Object.assign()
可以实现第一层的深拷贝,第二层就是浅拷贝了。咋说呐…真想不出来力。难道要纯手写个for循环去遍历拷贝?
递归实现深拷贝:
function deepClone(target) {
// WeakMap作为记录对象Hash表(用于防止循环引用)
const map = new WeakMap()
// 判断是否为object类型的辅助函数,减少重复代码
function isObject(target) {
return (typeof target === 'object' && target ) || typeof target === 'function'
}
function clone(data) {
// 基础类型直接返回值
if (!isObject(data)) {
return data
}
// 日期或者正则对象则直接构造一个新的对象返回
if ([Date, RegExp].includes(data.constructor)) {
return new data.constructor(data)
}
// 处理函数对象
if (typeof data === 'function') {
return new Function('return ' + data.toString())()
}
// 如果该对象已存在,则直接返回该对象
const exist = map.get(data)
if (exist) {
return exist
}
// 处理Map对象
if (data instanceof Map) {
const result = new Map()
map.set(data, result)
data.forEach((val, key) => {
// 注意:map中的值为object的话也得深拷贝
if (isObject(val)) {
result.set(key, clone(val))
} else {
result.set(key, val)
}
})
return result
}
// 处理Set对象
if (data instanceof Set) {
const result = new Set()
map.set(data, result)
data.forEach(val => {
// 注意:set中的值为object的话也得深拷贝
if (isObject(val)) {
result.add(clone(val))
} else {
result.add(val)
}
})
return result
}
// 收集键名(考虑了以Symbol作为key以及不可枚举的属性)
const keys = Reflect.ownKeys(data)
// 利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性以及对应的属性描述
const allDesc = Object.getOwnPropertyDescriptors(data)
// 结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链, 这里得到的result是对data的浅拷贝
const result = Object.create(Object.getPrototypeOf(data), allDesc)
// 新对象加入到map中,进行记录
map.set(data, result)
// Object.create()是浅拷贝,所以要判断并递归执行深拷贝
keys.forEach(key => {
const val = data[key]
if (isObject(val)) {
// 属性值为 对象类型 或 函数对象 的话也需要进行深拷贝
result[key] = clone(val)
} else {
result[key] = val
}
})
return result
}
return clone(target)
}
// 测试
const clonedObj = deepClone(obj)
clonedObj === obj // false,返回的是一个新对象
clonedObj.arr === obj.arr // false,说明拷贝的不是引用
clonedObj.func === obj.func // false,说明function也复制了一份
clonedObj.proto // proto,可以取到原型的属性
又或者,用第三方库!
比如Lodash库中的cloneDeep
方法
最后当然估计是看我很多都答得很差,属于那种有印象但是说不出来的情况。那就结束喽。Leader开始给我提建议,都一一听取记在心里啦。
最后
买本红宝书学起来吧。把浏览器工作原理也搞清楚再来投简历!再战!