文章目录
- 一、HTML相关面试题
- 二、CSS相关面试题
- 三、js面试题
- 四、DOM,BOM操作相关面试题
- 五、HTTP相关面试题
- 六、VUE相关面试题
- 1.v-show和v-if的区别
- 2.为何在v-for中使用key
- 3.描述vue组件生命周期(父子组件)
- 4.vue组件常见的通讯方式
- 5.描述组件渲染和更新的过程
- 6.双向数据绑定v-model的实现原理
- 7.对MVVM的理解
- 8.computed有何特点
- 9.为何组件data必须是一个函数
- 10.ajax请求应该放在哪个生命周期中
- 11.如何将组件所有的props传递给子组件
- 12.何时使用keep-alive
- 13.何时需要使用beforeDestory
- 14.vuex中action和mutation有何区别
- 15.使用vnode描述一个DOM结构
- 16.监听data变化的核心api是什么
- 17.vue如何监听数组变化
- 18.描述响应式原理
- 19.diff算法的时间复杂度
- 20.vue为何是异步渲染,$nextTick有什么用
- 21.vue常见性能优化方式
一、HTML相关面试题
1. 如何理解HTML语义化?
HTML语义化可以提高代码可读性,维护起来更加方便;
还有利于SEO(搜索引擎优化)。
2. 块元素和内联元素
块元素:独占一行,div,h1-h6,p,table,ul,ol等都属于块元素;
内联元素:不独占一行,span,img,input,button等;
二、CSS相关面试题
1.盒模型宽度的计算
2 * border + 2 * padding + width
2.margin纵向重叠问题
相邻元素的margin-bottom和margin-top会发生重叠,以数值大的为准,空白内容的标签也会重叠.
3.margin的负值问题
margin-top设置负值,元素会向上移动;
margin-left设置负值,元素会向左移动;
margin-right设置负值,右侧元素左移,自身不受影响;
margin-bottom设置负值,下方元素上移,自身不受影响。
4.BFC的理解和应用
BFC(block format context),块级格式化上下文,一块独立的渲染区域,内部元素的渲染不会影响到边界以外的元素.
形成BFC的条件:
1.float不是none;
2.position是absolute或fixed;
3.overflow不是visible;
4.display是flex,inline-block等。
BFC一般应用于清除浮动
5.如何实现双飞翼布局和圣杯布局,这俩布局的目的是什么?
目的: 三栏布局,中间一栏最先加载和渲染(内容最重要),两侧内容固定,中间内容随着宽度自适应,一般用于PC网页。
共同点:都是使用float布局,两侧使用margin负值,以便和中间内容横向重叠,防止中间内容被两侧覆盖,一个使用padding,一个使用margin。
6.absolute和relative分别依据什么定位?
relative依据自身定位;
absolute依据距离自己最近的且有定位的元素来定位。
7.垂直居中对齐的实现方式
行内元素且知道高度:text-align:center;line-height:自身的高度;
块元素:
1.flex布局实现水平垂直居中;
2.定位+top:50%+left:50%+transform:translate(-50%, -50%)
8.line-height如何继承?
如果写具体数值,比如50px,那么直接继承该数值;
写比例,比如2/1.5,那么继承该比例;
写百分比,如200%,则继承计算出来的值(和父元素的font-size相乘的值)。
三、js面试题
1.typeof能判断哪些类型?
typeof可以判断出基本类型的值:string,number,boolean,undefined,symbol;
typeof判断引用类型和null返回的都是‘object’;
typeof判断函数返回‘function’。
2.手写js深拷贝
// 准备数据
const obj = {
name: "zhangsan",
age: 22,
address: "xian",
phone: {
mobile: "11111111111",
mobile1: "22222222222",
},
};
// 声明函数
const deepClone = (obj) => {
// 如果obj是基础类型的数据,那么就不存在深拷贝,直接返回就行
if (typeof obj !== "object" || obj == null) {
return obj;
}
// 判断obj是数组还是对象,并声明一个res变量并接收结果
let res = obj instanceof Array ? [] : {};
// 遍历原对象
for (let key in obj) {
// 通过hasOwnProperty来判断对象中的key是否属于该对象本身的属性
if (obj.hasOwnProperty(key)) {
// 通过递归,将值赋值给res的key
res[key] = deepClone(obj[key]);
}
}
// 返回res,实现深拷贝
return res;
};
const obj1 = deepClone(obj);
obj.phone.mobile = "lisi";
console.log("obj: ", obj);
console.log("obj1: ", obj1);
3.如何准确判断一个变量是不是数组
1.Array.isArray(xx)方法
2.xx instanceof Array
4.如何理解原型和原型链
为了方便区分,这里把prototype称为显式原型,__proto__称为隐式原型;
原型:每个构造函数都有显式原型(prototype),通过这个构造函数构造出的实例会有一个隐式原型(proto),实例的隐式原型指向的就是构造出它的函数的显式原型。
原型链:构造函数的显式原型也有显式原型,这样从实例到构造函数的显式原型再到显式原型的显式原型,就形成一个链条,这就是原型链。
当在实例中查找属性和方法时,如果该实例中没找到,那么就会顺着原型链去一层层查找,这就是基于原型链的属性和方法的查找规则。
4.this的不同应用场景,如何取值
1.当作普通函数被调用,this指向的是window;
2.使用call,apply,bind方法,指向的是绑定的对象;
3.作为对象方法被调用,指向的是该对象;
4.在class中调用,this指向的是实例本身;
5.在箭头函数中调用,指向的永远是它上级作用域中的this。
5.闭包的应用
1.隐藏数据
2.做一个简单的cache工具
const createCache = () => {
// 闭包中的数据,不会被外部访问到
const data = {};
// 只提供api供外部使用
return {
set: (key, val) => {
data[key] = val;
},
get: (key) => {
return data[key];
},
};
};
const c = createCache();
c.set("a", 100);
console.log(c.get("a")); // 100
6.同步和异步的区别是什么?
同步会阻塞代码的运行,异步则不会
7.前端异步的应用场景
网络请求,定时任务
8.描述event loop机制
同步代码执行的过程中,如果碰到异步代码,会将异步代码挂起,继续执行同步代码
当同步代码执行完毕之后,就会触发event loop 事件轮询机制,但在event loop生效之前,如果dom结构发生了变化,都会重新渲染dom,然后它会去查看挂起的异步代码中是否有执行完毕的,如果有,就会去执行
9.什么是宏任务和微任务,两者区别
宏任务:setTimeout,setInterval,Ajax,DOM事件
微任务:Promise,async/await
微任务执行时机比宏任务更早,微任务是在dom渲染之前触发,宏任务是在dom渲染之后触发
10.promise的三种状态
三种状态: pending resolve rejected
状态的表现:pending状态,不会触发then和catch;resolve状态,会触发then;rejected状态,会触发catch。
then和catch改变状态:then和catch正常都会返回resolved,里边有报错则返回rejected;
四、DOM,BOM操作相关面试题
1.DOM是哪种数据结构
DOM是一种树形的数据结构
2.DOM操作常用API
3.property和attribute的区别
property修改对象属性,不会体现在html结构中;
attribute修改html属性,会改变html结构;
两者都有可能引起DOM重新渲染。
4.一次性插入多个节点,考虑性能
可以使用createDocumentFragment方法,创建一个代码片段,这时这个代码片段还没有插入DOM树中,然后把节点都插入到这个代码片段里,最后再把这个代码片段插入到dom树中.
五、HTTP相关面试题
1.从输入url到浏览器渲染出页面的过程
1.输入url之后,首先开始查找本地缓存,如果有,就直接返回,否则就开始DNS解析
2.通过DNS解析拿到IP地址,如果是HTTPS协议,就会建立tls连接,如果是http协议,就会建立tcp连接,进行三次握手
3.利用IP地址和服务器建立连接之后,向服务器发起请求
4.服务器收到请求信息后,会根据请求信息生成响应行,响应头,响应体并发给网络进程,网络进程开始解析响应头的内容
5.如果响应头中有301,302等状态码,那么网络进程就会从location字段中读取地址并重新发起请求
6.导航会根据content-type这个字段来判断响应体数据的类型,浏览器通过这个来判断如何显示响应体的内容
这时浏览器开始准备渲染页面:
1.准备渲染进程,渲染进程一般一个页面一个,如果同一站点(协议+根域名相同),就会复用
2.提交文档,浏览器开始渲染
3.先构建DOM树,然后将css文件变成cssom树,根据这两棵树生成渲染树,开始布局渲染
六、VUE相关面试题
1.v-show和v-if的区别
v-show相当于加了display:none样式,但dom元素依旧存在于DOM树中,一般用于频繁的隐藏或显示中
v-if则是将这个元素从DOM树中彻底移除掉,一般用于不频繁的隐藏或显示中
2.为何在v-for中使用key
diff算法中通过tag和key来判断,是否是sameNode,这样可以减少渲染次数,提升渲染性能
3.描述vue组件生命周期(父子组件)
挂载阶段:父组件beforeCreate,created,beforeMount,子组件beforeCreate,cerated,beforeMount,mounted,父组件mounted。
更新阶段:父组件beforeUpdate,子组件beforeUpdate,updated,父组件updated.
销毁阶段:父组件beforeDestory,子组件beforeDestory,destoryed,父组件destoryed.
4.vue组件常见的通讯方式
父传子(props),子传父(emit),兄弟传值(eventBus),vuex,路由传参等
5.描述组件渲染和更新的过程
解析template模板生成render函数,如果模板中没有胡子语法(Mustache,双大括号),那么直接生成vnode并渲染。如果模板中有胡子语法,那么就会触发响应式,watcher会监听触发了哪个getter,然后生成一个vnode并渲染出来。当修改这个getter的时候,会重新生成render函数,并生成一个新的vnode,然后通过pach函数和旧的vnode去对比后渲染出来。
6.双向数据绑定v-model的实现原理
input元素的value = this.name
绑定input事件,this.name = $event.target.value
当触发input事件时,data会更新,触发re-render。
7.对MVVM的理解
MVVM分为model,view,viewModel
model相当于vue中的data,数据一般都在model层中定义
view代表ui视图,负责展示数据
viewModel负责监听model中数据的改变并控制视图的更新,处理用户交互操作
model和view并无直接关联,而是通过viewModel来进行联系的,model和viewModel之间有双向数据绑定的联系,因此当model中的数据改变时会触发view层的刷新,view层中由于用户交互操作而改变的数据也会在model中同步
这种模式实现了model和view的数据自动同步,因此开发者只需要专注对数据的维护操作,不需要自己操作dom
8.computed有何特点
缓存,data不变的话不会重新计算,可以提高性能
9.为何组件data必须是一个函数
如果data不是一个函数,那么所有实例的data中的数据就是公共的,会互相影响.但data是函数就不一样了,data中的数据会形成一个闭包,生成的实例中的data都在闭包中,不会互相影响
10.ajax请求应该放在哪个生命周期中
mounted中,因为js是单线程的,必须等页面渲染完成后才会去执行异步操作获取数据,而created只是数据初始化完成了,并没有开始渲染,所以放在created中没有任何意义,它还是会等mounted钩子执行完毕页面渲染完成后才会异步获取数据。所以放在mounted中比较合适并且逻辑看起来更加清晰。
11.如何将组件所有的props传递给子组件
可以使用$props
12.何时使用keep-alive
缓存组件,不需要重复渲染
多个静态tab页的切换
优化性能
13.何时需要使用beforeDestory
解绑自定义事件
清除定时器
解绑自定义的DOM事件,如window scroll等
14.vuex中action和mutation有何区别
action中处理异步,mutation中不可以
mutation做原子操作
action可以整合多个mutation
15.使用vnode描述一个DOM结构
// dom结构
<div id="div1" class="container">
<p>vdom</p>
<ul style="font-size: 20px;">
<li>a</li>
</ul>
</div>
// vnode
{
tag: "div",
props: {
className: "container",
id: "div1",
},
children: [
{
tag: "p",
children: "vdom",
},
{
tag: "ul",
props: { style: "font-size:20px" },
children: [
{
tag: "li",
children: "a",
},
// ...
],
},
],
};
16.监听data变化的核心api是什么
object.defineProperty
缺点:
1.深度监听需要使用递归,导致计算量特别大;
2.这个api不能监听新增和删除,所以vue有了$set和$delete
17.vue如何监听数组变化
object.defineProperty不能监听数组变化,因此只能重新定义原型,重写push pop等方法,实现监听
18.描述响应式原理
通过object.defineProperty来监听数据,当取值或修改属性的值时,会触发数据的getter和setter,getter和setter方法内可以触发视图的更新,从而实现响应式
19.diff算法的时间复杂度
O(n)
在O(n^3)基础上做了优化,优化完成后时间复杂度就变为O(n):
1.只比较同意层级,不跨级比较
2.tag不相同,则直接删掉重建,不再深度比较
3.tag和key相同,则认为是相同节点,不再深度比较
20.vue为何是异步渲染,$nextTick有什么用
异步渲染可以提高渲染性能
$nextTick在DOM更新完之后,触发回调
21.vue常见性能优化方式
1.合理使用v-show和v-if
2.合理使用computed
3.v-for加key,避免和v-if同时使用
4.自定义事件,DOM事件及时销毁
5.合理使用异步组件
6.合理使用keep-alive
7.data层级不要太深