今年春节在每个人心中都会留下深深的烙印,也许若干年后回忆起来,我们会说,2020年可是全国人民足不出户过的年啊,那真是难以言语的春节,在抗击疫情面前,我们每个人都是英雄。缅怀,默哀!
说回正题
由于大环境的影响,其实早有预料今年的职业生涯将会不好过,只是没想到来的更早更彻底了一些,迫不得已才下定决心重新面临这个行业的择选与被选择。
开始准备工作
- 仔细捋一捋自己做过的项目,用的什么框架,其中有什么技术点,过程中遇到什么困难,如何解决的,然后修改简历;
- 因为比较粗心,所以也没有做过自己的前端知识导图(以后必须要做),回忆了一下前端技术中自己都会什么,能做什么,可以实现什么,大概是html5+css3+es6+webpack+vue+jQuery+HybirdAPP+thinkPHP,UI框架没有多大必要列举,可以在项目经历中一笔带过;
- 对于第2步中列举的知识有比较含糊的自己看博客,看视频,做笔记(俗话说好记性不如烂笔头),记的过程也是消化的过程。
进行阶段
其实就是正式开始投简历,然后约面试,今年这工作因为疫情催生出线上面试这个方式,有很多好处,首先节省了应聘者路程上花费的时间,其次就是反馈比较及时,面试情况当时就能知晓,另外就是对于没有回答完整或者卡壳的问题能够有充足的时间去弥补查验,在这个过程中我把自己面试中印象比较深刻的问题都记录了下来,想着等我找到工作之后就写篇总结,这就是我这篇文章的初衷。
最后结果
在经历了20多天的投简历,面试,查缺补漏之后,终于收到了满意的offer,接下来就是投入新环境,撸起袖子加油干了。在此也希望还在找工作的同行不要灰心,坚持,努力,幸运女神会眷顾你的~~~
下面分享我小本本上记录的比较常问的面试题
html+css+js基础
- 一个div如何做到水平垂直居中?
- 弹性伸缩盒布局,在其父元素上设置flex,又问具体设置哪些属性,当然是:
dispaly: flex; justify-content:center; align-items:center;
- 元素本身绝对定位absolute:0+margin:auto
position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;
- 绝对定位absolute+margin:-50%height:
position:absolute;left:50%;top:50%;margin:-1/2height;
- 绝对定位+css3位移
position:absolute;left:50%;top:50%;transform:translate(-50%, -50%);
- JS数据类型列举?
基本类型:Number,String,Boolean,Symbol,Null,Undefind
复合类型:Object
基本类型判断:typeOf,复合类型判断:Object.prototype.toString(),Object.getprototypeOf,intanceof
- 浅拷贝和深拷贝区别,如何实现?
深拷贝在计算机中开辟了一块新的内存地址用于存放复制的对象,而浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。
浅拷贝实现:object.assign(target,source)
深拷贝:①递归遍历所有层级,复制其属性和方法;②JSON.parse(JSON.stringify()),缺点是拷贝不到一些特殊值(正则表达式,undefine,function)
- 谈谈对闭包的认识?
- 首先闭包是函数套函数的形式,内部函数有权访问父函数的变量,参数和变量不会被垃圾回收机制收回。
- 它的用途:①可以读取内部函数的变量;②让这些变量的值始终保存在内存中,不会被调用后就被垃圾回收机制收回;③用来模块化代码(类似于块级作用域)
- 优点:①可以将一个变量长期储存在内存中;②避免全局变量的污染;③私有成员
- 缺点(这个当时有个面试官特意问的):①内存消耗大,网页性能受损,IE中内存泄漏(解决:退出函数之前,将不用的局部变量设为Null);②闭包会在父函数外部改变父函数内部变量的值
- __proto__和prototype有什么区别?
简单来说,prototype是一个对象的构造函数的原型,而__proto__是实例对象的一个属性,比如定义一个构造函数function A(){},这时候A就拥有了prototype,再实例化一个对象a,var a = new A(),这时a就拥有了__proto__属性,并且a.proto == A.prototype,再深入的话就是原型链相关的知识了,另当别论。
- 继承是什么?js如何实现继承
继承就是A对象通过继承B对象,就能直接拥有B对象的所有属性和方法。
实现继承的方式:①原型链继承(将父类的实例作为子类的原型);②构造函数继承(复制父类的实例属性给子类);③实例继承(为父类实例添加新特性,作为子类实例返回);④拷贝继承(遍历拷贝属性);⑤组合继承(通过调用父类构造函数,继承父类的属性并保留传参的优点,然后通过父类实例作为子类原型);⑥寄生组合继承(父类原型赋值给子类,并构造函数设置为子类);⑦class继承(extends语法)
- jQuery中trigger的作用是什么?
- 触发自定义事件,$('选择元素').trigger('clickMe', [data], fn() {})
- 模拟用户操作click
- 执行浏览器默认操作:比如input的focus
ES6基础
- 说说ES6常用功能?
- let/const
- 多行字符串/模板变量
- 解构赋值
- 块级作用域
- 箭头函数
- class语法
- 模块化
- Promise
- axios
- axios是基于什么封装的?
当时问到这个,我的回答是基于XMLHttpRequest()
封装,显然这不是面试官想要的完整答案,axios原理还属于XMLHttpRequest,因此需要实现一个ajax,但还需要一个promise对象来对结果进行处理,axios是一个基于promise的http库,支持promise所有的API。
- 数组map返回的是什么?
当时听到这个问题懵逼了,心里想map()遍历,返回的不就是每一次的key:value嘛,但是其实他想问的是map()返回的值和原数组的关系!首先说map()方法返回的是一个新数组,数组中的元素为原始数组元素调用函数处理后的值,不会改变原始数组。
- 箭头函数与普通函数的区别
有时候真的想掐死自己,这个问题回答的并不令人满意
- =>没有自己的this,继承的是外层代码块的this;
- 不可以当作构造函数,不可以使用New实例化;
- 不能使用arguments对象,该对象在函数体内不存在(可使rest)
- 不可以使用yield命令,因此=>不能用作Generator函数;
- 不能使用call,bind,apply改变this指向。
- 谈谈对prommise的理解,和async/await的区别?
promise是解决异步编程的一种方案,解决了异步处理回调金字塔问题,它有三种状态pending,resolve,reject,后面两个作为回调函数,分别表示成功回调和失败回调,可以用then(fn(){})进行链式调用,在catch(){}中捕获异常,在finally()里边做数据处理,promise().then(data => {}).catch(err => {}).finally(() => {}),还可以用promise.all()接收数组,返回结果...
1.async/await是写异步代码的新方式,以前的方法有回调函数和Promise。
2.async/await是基于Promise实现的,它不能用于普通的回调函数。
3.async/await与Promise一样,是非阻塞的。
4.async/await使得异步代码看起来像同步代码,这正是它的魔力所在。
- 异步解决方案有哪些?
这个问题当时也想掐自己,因为我就说了promise,ajax,人家问不用网络请求呢,我就emmm,真的太弱鸡了
正答:回调函数、事件监听、发布/订阅模式、promise、Generator、async/await
网页性能及网页操作相关问题
- 列举几个IE8相关的兼容性问题
- css3中background不支持连写;
- border-radius圆角不兼容,解决:下载PIE.htc文件,behavior:url('');
- box-shadow盒子阴影,同样htc文件;
- css3中background背景渐变,解决:progid:.....Microsoft.gradient()
- HTML5新标签兼容性,引入html5shiv.js;
- 媒体查询media,下载respond.min.js,引入到需要兼容的条件注释里边
- 在浏览器输入网址,页面发生了什么?
- DNS解析域名;
- 发送tcp请求;
- 发送http请求;
- 服务器处理请求并返回http报文;
- 浏览器解析渲染页面;
- 连接结束
记得有一个面试官问我,浏览器按什么顺序加载文件的?我当时只说渲染dom树,遇到js修改dom树,图片就重绘什么的,总之说的不好...详细的百度吧
- cookie,session有什么区别?
- 存储位置不同,cookie存放于浏览器,session存放在服务器上
- 存储容量不同不同,单个cookie不超过4kb,浏览器限制一个站点最多存储20个cookie
- session中存的是对象,cookie中存的是字符串
- 隐私策略不同,cookie对客户端时可见的,不安全;session存在服务器上,不存在敏感信息泄漏的风险
- 有效期不同,cookie可以长期有效,session只要关闭窗口就会失效
- 跨域支持不同,cookie可以跨域,session不可以。
- 网页什么操作会引起内存泄漏,如何防止?
- 意外的全局变量
- 闭包
- 没有清理的dom元素引用
- 被遗忘的定时器或回调
- 子元素存在引起的
如何防止:①减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收;②注意程序逻辑,避免死循环;③避免创建过多的对象
- 如何优化首屏加载时间?
- cdn分发;
- 后端缓存
- http缓存:hash+强缓存
- 组件,路由动态加载,图片懒加载
- 前端做一些接口缓存,通过内存和lacalstotage
- 页面使用骨架屏
- 图片格式压缩或者精灵图
- 利用好http压缩
- rem实现的原理是什么?
rem是根元素<html>确定一个px字号,就可以算出元素的宽高,假设rem的html设为16px,设计稿750px以375px量长宽,有个宽度100px,转换单位计算为100px/2/16px=3.125rem,再乘以缩放比例dpr
- 常见的移动端开发ios和andriod碰到的兼容性问题举例?
- js中的Date对象再safari中new Date('2020-04-10')是NaN,需字符替换,date.replace(/-/g, '/')
- 禁止图片放大pointer-events:none;
- 禁止页面缩放,touchstrart:touched
- 禁止ios识别长串数字为电话,<meta name="format-detection" content="telephone">
- 禁止复制,选中文本,-webkit-user-select:none
- 上下拉动滚动条时卡顿,反应慢,overflow-scrolling:touch
- 清除button、input、a标签的默认样式outline,border
- http与TCP的区别与联系?
TCP对应于传输层,HTTP对应于应用层。http协议是建立再TCP协议基础之上的,当浏览器要从服务器获取网页数据时,会发出一次http请求,http通过tcp建立一个到服务器的链接通道,当本次请求需要的数据发送接收完毕后,http会立即将tcp连接断开。
所以http是一种短连接,无状态。
tcp是底层协议,定义的是数据传输和连接方式的规范。
http是应用层协议,定义的是传输数据的内容和规范。
- http状态码,这个比较简单,就不做回答了
VUE+Webpack相关问题
- 说一说vue的生命周期?
beforeCreate:组件被创建,无data属性
created:属性绑定,没有dom.没有$el
beforeMount:模板挂载之前,生成虚拟dom
mounted:模板挂载之后,把data里的值渲染到模板
beforeUpdate:data改变的值赋值到相应属性
updated:更新到模板
bedoreDestory:销毁之前,可以清除定时器
destoryed:销毁组件,vue不再响应
- vue非兄弟之前传值
可以用vuex、eventBus、或者provide/inject
- vuex中action与mutation有什么区别?
action:异步请求,业务代码(不能直接操作state)
mutation:同步执行
- MVC和MVVM有什么区别?
mvc:单向通信,view和model必须通过controller来承上启下,在不改变视图的情况下改变视图对用户输入的响应方式,用户对view的操作交给controller处理,在c中响应了view的事件调用,m对数据进行操作,一旦model发生变化便通知相关视图进行更新。
mvvm:双向绑定。m(data)变化是view(html)可以实时更新,v变化也可以让model发生变化,vm(vue)。
- webpack热加载是什么?
hot reload,每次修改某个js文件后,页面局部刷新。基本原理是构建bundle的时候,加入一段HMRruntime的js和一段与服务器沟通的js,文件修改会触发webpack重新构建,服务器通过向浏览器发送更新消息,浏览器通过jsonp拉取更新的模块文件,jsonp回调触发模块热替换逻辑。
- v-for里面加key属性是什么作用?
节点的id标识,为了防止重复渲染导致的额外性能开销。
- webpack中loader和plugin的区别?
loader文件加载器,将A文件编译形成B文件,操作文件,比如A.SCSS->A.css
plugin扩展器,针对loader结束后,webpack打包的整个过程,不直接操作文件,二十基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务。
- 如何解决vuex页面刷新数据丢失问题?
监听浏览器刷新事件,在浏览器刷新之前把数据保存到sessionStorage/localStorage中,等获取到数据之后再更新赋值,如果没有请求到就使用存储的数据。
- VUE3有无了解?与VUE2有何区别?
创建的工程目录结构不一样了(自己体会吧~);响应式的实现原理不一样了,vue2采用object.defineProperty(),vue3使用proxy;compositionAPI组件引入方式不同,vue3按需单独引入,都放在setup(){};优化了渲染,块级数的优化(v-if,v-for),静态数缓存(重用相同节点);vue3支持ts,vue3更轻量...
算法相关题目
- 说几个熟悉的排序算法?
冒泡排序比相邻,插入排序建有序列,归并排序小合并,快速排序找基准,希尔排序设增量(这是我自己总结的顺口溜)。其中抽查问了一个希尔排序的实现思路,我很自信的说错了,说完我就低头找老鼠洞了改天再专门写这几个算法的具体实现吧
- 写一个算法实现一个数组中的任意两个元素值相加是否等于k,是返回true,否返回false
function foo(nums, k) {
let flag = false
if (nums.length <= 1) {
return flag
}
for (let i = 0; i < nums.length - 1; i++) {
for (let j = i+1; j < nums.length; j++) {
let sum = nums[i] + nums[j]
if (sum === k) {
flag = true
return flag
} else {
flag = false
}
}
}
return flag
console.log(flag)
}
foo([2, 4, 6, 7], 20)
- 写一个时间复杂度为O(nlogn)的算法
/** 快速排序算法
* 思路:
*1.每次选中一个被比较的标准数
* 2.标准数与数组中下标为i的元素比较,若标准数大于arr[i],交换位置
* 3.标准数与数组中下标为j的元素比较,若标准数小于arr[j],交换位置
* 4.每循环一轮,排出标准数的位置,并且改变标准数的值
* 递归2,3步,得出最终排序
*/
function QuickSort(arr, i, j) {
if (i < j) {
let left = i; let right = j;
let pivot = arr[left];
while (i < j) {
while (arr[j] >= pivot && i < j) { // 从后往前找比基准小的数
j--;
}
if (i < j) {
arr[i++] = arr[j]
}
while (arr[i] <= pivot && i < j) { // 从前往后找比基准大的数
i++;
}
if (i < j) {
arr[j--] = arr[i]
}
}
arr[i] = pivot;
QuickSort(arr, left, i - 1);
QuickSort(arr, i + 1, right)
return arr
}
}
QuickSort([23, 4, 13, 5], 0, 3)
- 给定一个json,转换json字符串为树结构
function jsonToTree(data) {
let resData = data
let arr = []
for (let i = 0; i < resData.length; i++) {
if (resData[i].pid === "0" && resData[i].layer === 1 && !resData[i].finalFlag) {
let obj = {
id: resData[i].id,
title: resData[i].title,
layer: resData[i].layer,
children: []
}
arr.push(obj);
resData.splice(i, 1);
i--;
}
}
treeToDeep(arr, resData)
return arr
}
function treeToDeep(SecArr, resData) {
const resDatas = resData
if (resDatas.length > 0) {
for (let j = 0; j < SecArr.length; j++) {
for (let k = 0; k < resDatas.length; k++) {
if (SecArr[j].id === resDatas[k].pid) {
let nObj = {
id: resDatas[k].id,
title: resDatas[k].title,
layer: resDatas[k].layer,
children: []
}
SecArr[j].children.push(nObj);
resDatas.splice(k, 1);
k--;
}
}
treeToDeep(SecArr[j].children, resDatas)
}
}
}
其实总结起来也不难,就是问的知识面比较广,复习一下起码一面能过了,本次面试题目就分享到这里,与君共勉,如有不当之处,评论区指正~~~