单纯为了自己面试方便,整理一些高频面试题,2023希望每个前端小伙伴找到心仪的工作!!
目录
「自我介绍(仅供参考)」
「HTML、CSS相关」
» H5有哪些新特性?
» 浏览器渲染机制、重排、重绘
» 简述CSS盒模型
» 如何让盒子水平垂直居中
» 如何实现一个三角形?
» CSS样式优先级
» 什么是BFC?BFC布局规则是什么?如何创建BFC?
「JS」
» 什么是闭包?
» 作用域、作用域链、变量提升、函数提升分别是什么?
» JS有哪些数据类型?typeof、instanceof、类型转换
» 原型和原型链
» 继承(含ES6)、多种继承方式
» this指向、new关键字
» bind、call、apply的区别?
» JS 的设计模式?
» 深拷贝和浅拷贝
» TS 和 JS 有什么区别,优点和缺点
» 什么是事件冒泡、事件捕获、事件委托机制?
» 普通事件和事件绑定有什么区别?
» EventLoop(线程机制)
» 防抖和节流
» 函数柯里化
「ES6」
» var 、 const、 let 的区别?
» Promise的理解
» Promise.all 和 Promise.race
» 箭头函数和普通函数的区别?
» map 和 forEach 的区别?
「Ajax API模块」
» ajax同源策略的理解,如何解决跨域?
» HTTP状态码有哪些?
» get 和 post 的区别?
» HTTP 和 HTTPS 的区别?
» 浏览器从输入url到渲染页面,发生了什么?
» 输入url 后 http请求的完整过程是什么?
「Vue2和Vue3」
» vue2 和 vue3的区别?
» vue2相比vue3有什么缺点?
» vue3有哪些新特性吗?它们带来什么影响
» vue2 数据双向绑定原理
» v-model的实现以及实现原理?
» MVVM开发模式的理解?
» vue组件通信有哪几种方式?
» 的作用是什么?或者vue切换页面如何保存状态?
» vuex有哪几种属性?
» vue-router路由实现原理是什么?有什么不同
» $route 和 $router的区别?
» vue中key 的作用是什么?
» 虚拟DOM和真实DOM的区别?
» computed 、watch 、methods的区别?
» 组件中的data为什么是一个函数?
» v-if 和 v-show的区别?
» vue数据变化视图不更新如何解决?
» 父子组件生命周期渲染顺序?
「前端性能优化」
» 前端性能优化的几种方式
» Vue首屏渲染优化有哪些?
» CDN加速静态资源是什么?
「前端工程化」
» express 和 koa 有什么区别?
» webpack配置
» 前端为什么要进行打包和构建?
» webpack的基本功能有哪些?
» 常见的Webpack Loader?解决什么问题
» Loader 和 Plugin 的不同?
» 有哪些常见的 Plugin插件?解决什么问题的?
» Vite 和 Webpack区别?
» 为什么Vite 比 webpack速度快?
「职业技能规划、人事面试」
» 你的职业规划是什么?
» 为什么从上一家公司离职?
» 前端是如何学习的?
» 项目中有遇到什么难题?
» 还有什么想问的?
注意: 别紧张,目光注视面试官,不要有小动作,自信!!自信!!自信!!
面试官您好,我叫XXX,目前从事前端开发工作已经有X年,我上家公司是一个外包公司做别人的项目的,主要从事H5页面,后台管理系统和小程序等项目开发,其中H5和PC端是一套做保险相关业务的,在做H5的时候遇到过一个bug就是做微信分享SKD签名无效,请求的后台数据也返回了,后端就反映不是自己的问题,但反复排查发现是后端返回的签名和公众号配置的签名不一致,导致签名无效,分享失败...我呢平常喜欢逛一些技术社区丰富自己的技术,像知乎,掘金之类,并且自己也独立开发了个人博客网站,记录自己的工作总结和学习心得。 我的性格比较温和,跟同事朋友相处时比较外向,在工作中代码开发时我喜欢全心全意的投入,对于工作我也抱着认真负责的态度。面试官,以上是我的介绍,谢谢。
语义化指的就是合理正确的使用语义化标签来创建页面结构,如:
header、nav、footer,从标签上就能看出这个标签的作用,而不是滥用div
语义化的优点:
代码结构清晰,易于阅读、利于开发和维护
方便其他设备解析(如屏幕阅读器)根据语义渲染网页
有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重
网页生成过程:
重排(也叫回流):当改变DOM元素位置和大小时,浏览器需要重新计算元素的几何属性,将其安放在接界面的正确位置,这个过程叫做重排
触发:
重绘: 当一个元素的外观发生改变,但布局没有发生变化,重新绘制外观的过程
触发: 改变元素的 color、 background、box-shadow等属性
总结:重排一定会引起重绘,重绘不一定会引起重排,重排的性能消耗比重绘大
如何避免性能影响?
.box {
width: 0;
height: 0;
line-height: 0;
font-size: 0;
border: 50px solid transparent;
border-left-color: pink;
}
想要哪个方向的三角设置哪个方向的边框颜色
!important(无穷大) > 行内样式(1000) > id选择器(100) > 类选择器(10)、属性选择器、伪类选择器 > 标签选择器、元素选择器(1) > 继承或 *通配符选择器(0)
共同点: 都用来隐藏元素
不同点:
浮动的元素会脱离文档流,什么叫脱离文档流,举个栗子: 有一天你和你老板说:世界那么大,你想去看看,那之后你老板就管不了你了。脱离文档流也同理,一个元素一旦浮动,就会脱离文档流,那父元素也就管不了他了,布局就会往前推进, 父元素就会出现 高度塌陷 的问题。
BFC是块级格式化上下文,是CSS布局的一个概念,是一个环境,里边的元素布局不会影响到外面的元素布局
布局规则(原理):
A.内部的box会在垂直方向,一个接一个的放置
B.box垂直方向的距离由margin决定,属于同一个BFC的两个box 的margin会发生重叠
C.BFC的区域不会与float元素box重叠
D.BFC是一个独立的容器,里边的子元素不会影响外边的元素
E.计算BFC高度的时候,浮动元素也会参与计算
哪些元素会生成BFC?
从安全性来说,因为每次http请求都会携带cookie,这样浪费了带宽,所以cookie尽可能少用,此外cookie需要指定作用域,不能跨域调用,限制很多;local和session可以用来在页面传递参数,session可以保存一些临时的数据,防止用户刷新页面丢失一些参数
通俗一点就是打通了一条函数外部访问函数内部作用域的通道,正常情况下函数外部是访问不到函数内部作用域变量的
如何判断闭包: 函数嵌套函数、内部函数被return、内部函数调用外层函数的局部变量
优点: 隔离作用域,不造成全局污染
缺点: 导致函数变量一直保留在内存中,过多的闭包会导致内存泄露(任何对象不需要它后仍然还在)
闭包的主要作用: 延伸变量的作用范围
适用场景: 封装组件、for循环和定时器结合、节流和防抖也会用到
vue中出现内存泄露的情况:
作用域: js识别变量的范围,包括全局作用域(任何地方都可访问的变量)、局部作用域(只在函数内部定义的变量范围)、块级作用域(ES6用const、let定义的变量都认为是块级作用域中的变量)
作用域链: 从当前作用域开始一层一层向上寻找某一个变量,直到找到全局作用域还是没找到,就放弃!这查找的过程,就是作用域链
变量提升: 使用var关键字定义的变量,只提变量,不提赋值
函数提升: 使用function声明的函数,只提函数,不调用函数
js属于弱类型语言(支持隐式转换)
数据类型: String、Number、Boolean、Null、undefined、Object(function,array--堆内存)、symbol(ES10BigInt--栈内存)
typeof: 基本数据类型除了null返回Object,其他都返回对应的类型; 引用数据类型除了函数其他都返回Object
instanceof: 判断该对象是谁的实例
null表示空对象,undefined表示已在作用域中声明但未赋值的变量
原型: js中万物皆对象,每一个对象都有自己的属性,js中如何让多个对象共用一个或多个方法呢?原型的出现就是为了解决这个问题,每一个对象都有一个与他关联的原型对象,每次获取对象属性都是一次查找过程,在对象的自有属性中找不到就会去查找它的原型对象
原型链: 原型连成一条链,当我们访问一个对象的属性时,如果这个对象内部没有这个属性,我们就会去它的原型对象中查找这个属性,这个原型对象又会有自己的原型,于是这样一直向上查找,直到找到Object为null的时候,这个查找的过程就是原型链
总结:
new操作符干了什么?
浅拷贝: 只拷贝最外层对象,更深层次的对象只拷贝引用地址,而且改变一个对象属性值,另一个对象属性也会发生改变,即互相影响; 用ES6的 Object.assign({}, {})浅拷贝进行对象合并,ES6扩展运算符
深拷贝: 拷贝最里层的数据,利用递归函数;即改变一个对象属性,另一个对象属性值不会发生改变,可以通过JSON.parse(JSON.stringify(对象))的方式实现深拷贝,缺点 不可拷贝 undefined、function、RegExp类型的数据
TS是JS的超集,可以在ts中使用原生的 js 语法; JS是一种脚本语言,用于创建动态网页
TS是强类型语言,支持静态和动态类型; JS是动态弱类型语言
TS可以在编译期间发现错误; JS只能在运行时发现错误
TS不允许改变变量的数据类型; JS变量可以被赋予不同类型的值
TS优点:
1. 提供了静态类型检查,可以在编译时捕获一些常见的错误
2.包含了更多类型信息和注释,便于阅读和理解
3.提供更好的代码提示和自动补全功能,可以提高开发效率
JS的优点:
1. 直接在浏览器中运行,不需要编译成其他语言
2.具有广泛的应用和强大的生态系统,有大量的库和工具
3.可以快速迭代开发,适合小型项目
事件冒泡:子元素事件的触发会影响到父元素事件;从内而外,关闭事件冒泡: e.stopPropagation()
事件捕获:父元素的事件会影响到子元素的事件;从外而内,阻止默认行为:e.preventDefault()
事件委托:某个事件本来是自己干,但自己不做交给别人来干,利用冒泡处理子元素的事件
提高性能: 如当有很多li同时需要注册事件时,如果使用传统方法来注册事件的话,就需要给每一个li注册事件,但如果使用事件委托,只需要将事件委托给父元素即可
普通事件的onclick只支持单个事件,而且会被其他onclick事件覆盖;且不可以取消
事件绑定addEventListener可以添加多个事件,也不会被覆盖,绑定后可用removeEventListener取消
js一大特点就是单线程,也就是说,同一个时间只能做一件事
单线程就意味着,所有任务都需要排队,前一个任务结束,后一个任务才会执行,如果前一个任务耗时很长,后一个任务不得不等着; 于是所有任务分为两种同步任务和异步任务,异步队列又分为宏任务和微任务队列,宏任务执行时间长,所以微任务优先于宏任务;
微任务: .then、async、await、.catch、.finally
宏任务: setImmediate、setTimeout、setInterval、ajax请求、读取文件、DOM事件
执行顺序: 同步——promise、process.nextTick——微任务——宏任务
同步任务: 代码一行行执行,前面代码没有执行完.后面代码就不会执行,代码阻塞
如: 烧水做饭,必须等水开10分钟之后,再去切菜、炒菜(强调执行的顺序)
异步任务: 当前代码没有执行完,可以执行后面代码
如:烧水的同时,利用10分钟切菜、炒菜(不按顺序执行,解决代码阻塞,提升代码执行效率和性能)
防抖(debounce): 一定时间连续触发,只在最后执行一次,比如:搜索事件,用户在不断的输入值时,用防抖来节约请求资源,只有最后一次回车才能返回结果; 用户按钮的点击事件,为了防止多次重复提交也会使用防抖,减少请求次数,节约请求资源,不消耗性能
如: 坐公交,司机需要等最后一个人上车才能关门,每上一个人,司机就会多等待几秒在关门
节流(throttle): 一段时间内只执行一次; 如:页面滚动事件,是否滑到底部自动加载更多;csdn写文章,边写边保存
如: 一个水龙头在滴水,可能一次会滴很多,但我们希望500ms滴一滴,保持这个频率;希望函数在一个可以接受的频率重复调用
防抖(简单版本):
function debounce(fn, delay) {
let timer = null
clearTimeout(timer); 清除上次定时器,然后重新延迟
timer = setTimeout(function () {
fn()
}, delay)
}
将多个参数的函数改为一个参数的函数
函数柯里化-经典面试题
// 通过typeofTest生成:
// 动态传入判断的类型
const typeofTest = function (type) {
function isUndefined(thing) {
return typeof thing === type
}
return isUndefined
}
// 简化版:
const typeofTest1 = type => thing => typeof thing === type
const isString = typeofTest('string')
console.log(isString('1111'))
新增symbol类型 表示独一无二的值,用来定义独一无二的对象属性名;
const/let 都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,也就是不存在变量提升。(const一般用于声明常量);
变量的解构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(...rest);
模板字符串(${data});
扩展运算符(数组、对象);;
箭头函数;
Set和Map数据结构;
Proxy/Reflect;
Promise;
async函数;
Class;
Module语法(import/export),解决命名冲突,提高复用性,提高代码可维护性
async function fun1() {
let data = await fun2()
console.log(data) //then中执行的代码
}
async function fun2() {
console.log(200) // 同步
return 100
}
fun1() // 200 100
// 1、3、5、8、2、6、7、4
console.log(1)
async function async1() {
await async2()
console.log(2)
}
async function async2() {
console.log(3)
}
async1()
setTimeout(() => console.log(4),0)
new Promise(resolve => {
console.log(5)
resolve()
}).then(function() {
console.log(6)
}).then(function() {
console.log(7)
})
console.log(8)
promise.all可以将多个promise实例包装成一个新的promise实例。同时,成功和失败的返回值是不同的,成功的时候返回一个数组,失败的时候返回最先被reject失败状态的值。
promise.race 就是赛跑的意思,哪个结果获取的最快,就返回哪个结果,不管结果本身是成功还是失败状态
定义参数:如果只有一个参数可以不写括号,函数体只有返回值可以不写return
this指向不同: 普通函数this谁调用指向谁,箭头函数this在哪里定义,this就指向谁
共同点: 都是用来做循环的; 每次循环都支持三个参数,当前项、索引、原数组; 函数this都指向window
不同点: 1.forEach没有返回值; 2. map有返回值可以return,返回一个新数组
同源策略是浏览器的一种安全机制,防止他人恶意攻击网站,如果协议、域名、端口号有一个不同就会产生跨域(及域名和ip地址访问);跨域请求产生时,请求是发出去了,也是有响应的,仅仅是浏览器同源策略,认为不安全拦截了结果,不将数据传递给前端使用
img、link、script标签允许跨域加载
如何解决跨域:
三个方面:
网络篇:
构建请求
查找强缓存
DNS解析
建立TCP连接(三次握手)
发送HTTp请求(网络请求后网络响应)
浏览器解析篇:
解析html构建DOM树
解析css构建CSS树,样式计算
生成布局树(Layout Tree)
浏览器渲染篇:
建立图层树(Layer Tree)
生成绘制列表
生成图块并栅格化
显示器显示内容
最后断开连接:TCP 四次挥手
(浏览器会将各层的信息发送给GPU,GPU会将各层合成,显示在屏幕上)
建立TCP连接——发送请求行——发送请求头——(到达服务器)发送状态行——发送响应头——发送响应数据——断开TCP连接
重写虚拟DOM
可以期待更多的编译时提示来减少运行时的开销 优化插槽生成
可以单独渲染父组件和子组件 静态树提升
降低渲染成本 基于Proxy的观察者机制
节省内存开销检测机制
更加全面、精准、高效,更具可调试式的响应跟踪核心主要通过数据劫持结合发布者-订阅者模式来实现的。
通过Object.defineproperty()来劫持各个属性的getter和setter,在数据变动的时候发布给订阅者,触发相应的监听回调渲染视图,缺点就是没办法监听到数组的变化, vue3的proxy可以直接监听对象和数组的变化,并且有多达13种拦截方法
本质上就是一个语法糖,可以看成是value+input方法的语法糖。可以通过model属性的prop和event属性来进行自定义。原生的model会根据标签的不同生成不同的事件和属性。
MVVM是Model-View-ViewModel的缩写,Model代表数据模型,View代表ui组件,ViewModel代表桥梁,当数据发生变化的时候,视图也发生变化,当视图发生变化的时候,数据也会跟着同步变化
内置组件,一般结合路由和动态组件,实现组件缓存,一般用在用户频繁点击的地方
keep-alive提供include、exclude属性,两者都支持正则表达式和字符串
include: 只要匹配的组件就会被缓存
exclude: 任何匹配的组件都不会被缓存,优先级高
keep-alive对应两个钩子函数: activated 组件渲染后调用; deactivated组件销毁后调用
例如: 有一个列表页和详情页,用户一直来回高频率切换两个页面,一直在进行挂载销毁挂载销毁,消耗资源,可以使用keep-alive进行缓存,这样来回切换的时候直接从缓存里渲染,而不是重新渲染
实现流程:
路由本质上就是建立URL和页面之间的映射关系,路由实现原理的核心之一就是“更新视图但不重新请求页面”,目前实现路由主要两种方式:1.url中的hash 2.H5中的history
不同点:
$router: 为路由实例,是全局路由对象,包含路由跳转方法,钩子函数等,$router.push() $router.go(1)
$route: 路由信息对象|| 跳转的路由对象,包括:name,params,path,query,hash,fullPath,matched参数
key的作用主要是为了高效的更新虚拟DOM
好比给你起名字,如果没有名字,渲染列表是不是从0-100得重新渲染,如果你有名字的情况下,刚好你名字对应的数据变动了,然后根据名字直接找到这个值修改就好,就不需要重新渲染了
实际得到的数据不能直接在页面中展示,需要做一些处理,就使用computed
一个组件被复用多次的话,也会创建多个实例,本质上,这些实例用的是同一个构造函数,如果data是对象的话,对象是引用类型,会影响到所有的实例,为了保证组件不同的实例之间data不冲突,data必须是一个函数,data是闭包,函数被return,对象在栈中存的都是地址,函数的作用就是属性私有化,保证组件修改自身不会影响到其他复用组件
v-if 直接创建和销毁DOM让元素显示和隐藏
v-show 通过css属性 display:none来控制显示和隐藏
如果频繁切换,使用v-show; 反之v-if, v-if消耗性能
在created中操作DOM报错,在这个时候vue实例没有挂载,获取不到DOM,可以使用this.$nextTick(()=>{})回调函数获取DOM
加载渲染过程: 父beforeCreate、父created、父beforeMount、子beforeCreate、子created、子beforeMount、子mounted、父mounted
子组件更新过程: 父beforeUpdate、子beforeUpdate、子updated、父updated
父组件销毁过程:父beforeDestory、子beforeDestory、子destoryed、父destoryed
常用的生命周期: created获取数据, mounted操作Dom, beforeDestory销毁实例防止内存泄露
1. 浏览器缓存
2. 防抖、节流
3. 资源懒加载、预加载
4.开启Nginx gzip压缩
三个方面来说明前端性能优化
一: webapck优化与开启gzip压缩
1.babel-loader用 include 或 exclude 来帮我们避免不必要的转译,不转译node_moudules中的js文件
其次在缓存当前转译的js文件,设置loader: 'babel-loader?cacheDirectory=true'
2.文件采用按需加载等等
3.具体的做法非常简单,只需要你在你的 request headers 中加上这么一句:
accept-encoding:gzip
4.图片优化,采用svg图片或者字体图标
5.浏览器缓存机制,它又分为强缓存和协商缓存
二:本地存储——从 Cookie 到 Web Storage、IndexedDB
说明一下SessionStorage和localStorage还有cookie的区别和优缺点
三:代码优化
1.事件代理
2.事件的节流和防抖
3.页面的回流和重绘
4.EventLoop事件循环机制
5.代码优化等等
首先呢您肯定在京东自营买过东西,在京东买东西基本隔天就能到货,这是为什么呢?
细心的话就会发现京东发货地址离我们很近,那是因为京东将商品放在八大仓库里,我们从京东买东西会从就近的仓库发货,这样就省去了物流时间,基本第二天就能送到,速度很快
那当我们访问网络时,我在北京访问一个网络,站点服务器在上海,这个时候访问速度是不是会变慢,那怎么才能向京东买东西一样快速到货,就用到了CDN
CDN就是你的网站缓存,而CDN节点相当于京东八大仓库,把网站内容存到了CDN节点,然后每个请求网站的用户就近获取网站数据,大大减短了长距离传输和网络拥堵的情况下的访问速度
1. 语法区别
2. 中间件区别
3. 集成度区别
module.exports={
entry: {},
output: {},
plugins:[],
module: [ rules: [{}] ]
}
代码层面:
研发流程方面:
不同的作用:
不同的用法:
html-webpack-plugin
:简化 HTML
文件创建 (依赖于 html-loader
)uglifyjs-webpack-plugin
:压缩js文件clean-webpack-plugin
:目录清除一专多精
我一般回答主要两个原因: 1、想学更多的东西 2、老生常谈当然薪资呗
面试官问怎么学习前端,这种问题一般考察: 学习能力
一开始学习前端,主要靠视频和书籍,主要是总结很多知识点,但发现学习过程中理论大于实操,所以自己把知识点总结后开始找项目实操,这样一步步成长起来的,平时在工作中也会碰到很多问题,一般都是自己查找原因并和同事一起来交流,然后自己会总结一些学习文档,方便日后查看和积攒经验,所以我感觉我的学习都是实操加总结
可以说由于之前的业务相对常规,没有遇到太大的困难,但是也比较期待在今后的工作中遇到一些难题,因为这样才能让我成长; 也可以说些自己项目遇到了什么难题bug
一般问技术团队的规模
然后就是技术栈
然后是自己在团队中的角色
问清楚工资什么时候发,公积金的缴纳比例,有没有涨薪和晋升的机会,有没有普调,在几月调薪,能不能提前通过试用期.....
最后祝大家,都能找到满意的工作,升职加薪,一个个成为富婆!!