前端面试(真题重现,确定不进来看看?)

前端面试(真题重现,确定不进来看看?)_第1张图片
前端面试(真题重现,确定不进来看看?)_第2张图片
前端面试(真题重现,确定不进来看看?)_第3张图片
前端面试(真题重现,确定不进来看看?)_第4张图片

setTimeout(function() {
    console.log('宏任务setTimeout');  //先遇到setTimeout,将其回调函数注册后分发到宏任务Event Queue
  //如果setTimeout设置时间,那它会先把函数放到宏任务Event Table,等时间到了再放入宏任务Event Queue里面
})
new Promise(function(resolve) {
    console.log('微任务promise');  	//new Promise函数立即执行
    resolve();						//必须resolve执行才能执行then
}).then(function() {
    console.log('微任务then');  		  //then函 Queue
})
console.log('主线程console');
 
//执行顺序结果: 微任务promise、主线程console、微任务then、宏任务setTimeout

一、前端常见的兼容性问题

1:不同浏览器的标签默认的外补丁( margin )和内补丁(padding)不同
解决方案: css 里增加通配符 * { margin: 0; padding: 0; }
2:IE6双边距问题;在 IE6中设置了float , 同时又设置margin , 就会出现边距问题
解决方案:设置display:inline;
备注:我们最常用的就是div+CSS布局了,而div就是一个典型的块属性标签,横向布局的时候我们通常都是用div float实现的,横向的间距设置如果用margin实现,这就是一个必然会碰到的兼容性问题。
3:当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度
解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度
备注:这种情况一般出现在我们设置小圆角背景的标签里。出现这个问题的原因是IE8之前的浏览器都会给标签一个最小默认的行高的高度。即使你的标签是空的,这个标签的高度还是会达到默认的行高。
4:图片默认有间距
解决方案:使用float 为img 布局
备注:因为img标签是行内属性标签,所以只要不超出容器宽度,img标签都会排在一行里,但是部分浏览器的img标签之间会有个间距。去掉这个间距使用float是正道。
5:光标手形:cursor:hand 在safari 上不支持 IE才支持
解决方案:统一使用 cursor:pointer
6:解决在 IE6 下,列表与日期错位的问题
日期 标签放在标题 标签之前即可
7:IE6-7 line-height 失效的问题
问题:在ie 中 img 与文字放一起时,line-height 不起作用
解决:都设置成 float
8:两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative ;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;
解决方案:父级元素设置position:relative
9:上下(边距)margin的重叠问题
描述:给上边元素设置了margin-bottom,给下边元素设置了margin-top,浏览器只会识别较大值;
解决方案:margin-top和margin-bottom中选择一个,只设置其中一个值;
10:表单元素行高不一致
解决方案:给表单元素添加float:left(左浮动);或者是vertical-align:middle;(垂直对齐方式:居中)

二、vue中怎么重置Data

使用Object.assign()

// 重置data数据
Object.assign(this.$data, this.$options.data())

三、vue组件中name的作用

1.当项目使用keep-alive时,可搭配组件name进行缓存过滤
举个例子:
我们有个组件命名为detail,其中dom加载完毕后我们在钩子函数mounted中进行数据加载
2.DOM做递归组件时:比如说detail.vue组件里有个list.vue子组件,递归迭代时需要调用自身name
3.当你用vue-tools时
vue-devtools调试工具里显示的组见名称是由vue中组件name决定的

四、vue—router、routes、route的区别

1.routerthis.$router 是路由【导航对象】,用它 可以方便的 使用 JS 代码,实现路由的 前进、后退、 跳转到新的 URL 地址
vue-router有两种模式:
hash router 有一个明显的标志是url 中带有#, 我们可以通过监听url中的hash来进行路由跳转
history:比如history.back() 就能轻松的做到页面回退
2.routes:指创建vue-router路由实例的配置项。用来配置多个route路由对象
3.routethis.$route 是路由【参数对象】,所有路由中的参数, params, query 都属于它
前端面试(真题重现,确定不进来看看?)_第5张图片

五、JS通用的事件注册函数

function addEvent(element, type, handler)
{
    if (element.addEventListener)
    {
        element.addEventListener(type, handler, false);
    }
    else if (element.attachEvent)     //for IE
    {
        element.attachEvnet(“on” + type, handler);
    }
    else
    {
        element[“on” + type] = handler;
    }
}

六、vue-router路由跳转分为两大类

1.命名路由搭配params,刷新页面参数会丢失
2.查询参数搭配query,刷新页面数据不会丢失
3.接收参数使用this.$router后面就是搭配路由的名称就能获取到参数的值
前端面试(真题重现,确定不进来看看?)_第6张图片

六、前端性能优化方法总结

  1. 内容层面
    ① DNS解析优化(DNS是域名系统, 浏览器访问域名的时候,是需要去解析一次DNS,也就是把域名google.com解析到对应的ip地址上)
    减少DNS查询次数(首先查看浏览器缓存是否存在,不存在则访问本机DNS缓存,再不存在则访问本地DNS服务器。所以DNS也是开销,通常浏览器查找一个给定URL的IP地址要花费20-120ms,在DNS查找完成前,浏览器不能从host那里下载任何东西。);
    ② 避免重定向
    重定向至少访问两个不同地址,会减慢访问速度;(301重定向,从“重定向”的意思本身我们能明确是指向一个新的地址。也就是说是将现在的地址重新指向一个新的地址。大白话上我们可以理解为是网页的跳转。301是http协议中的一个跳转协议,301重定向就是当前页面永久性的跳转到一个新的地址上了。)
    ③ 杜绝404
    404代表服务器没有找到资源,网页中需要加载一个外部脚本,结果返回一个404,不仅阻塞了其他脚本下载,客户端还会将下载回来的内容(404)当成JavaScript去解析。

2)网络传输阶段
① 减少传输过程中实体的大小
b. cookie优化
去除没有必要的cookie,如果网页不需要cookie就完全禁掉。将cookie的大小减到最小。设置合适的过期时间,较长的过期时间可以提高响应速度。
c. 文件压缩
压缩传输文件通常可以减少70%网页内容的大小,包括脚本、样式表、图片等文件。
② 减少请求的次数
a. 文件适当的合并
将多个JS脚本文件合并成一个文件,将多个CSS样式表文件合并成一个文件,以此来减少文件的下载次数。
b. 雪碧图
把小图标合成一张大图,通过给元素的公共css设置background-image为该合成图,这样每个元素都会以该合成图为背景,而且页面也只加载一张合成图,然后再给每个元素单独微调其background-position。把多个请求合并成一个。
③ 异步加载
通过async和defer关键字或动态创建

  1. 渲染阶段
    ① js放底部,CSS放顶部
    将js脚本置底,可以让网页渲染所需要的内容尽快加载显示给用户。浏览器在CSS全部传输完全之前不会去渲染任何的东西,将CSS放在文档顶部能使页面加载得更快。
    ② 减少重绘和回流
    重绘和回流会延长网页的加载时间。
    减少重绘和回流的方法有:①将多次改变样式属性的操作合并成一次操作。
    ②用transform 代替 top,left ,top, margin-left… 这些位移属性
    当渲染树(render tree)中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
    当渲染树(render tree)中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建,这就称为回流(reflow)。
    区别:回流必将引起重绘,而重绘不一定会引起回流。
    ③ 减少DOM节点。(那么dom操作为什么慢?
    这就要提及浏览器渲染页面,浏览器分为:渲染引擎和js引擎。
    渲染引擎工作:
    1、解析HTML代码,生产DOM tree。
    2、解析CSS样式,结合DOM tree生产Render tree(display:none;的结点不会存在Render tree上,最后不会被paint)。
    3、计算Render tree 各个节点的布局信息,比如box的位置、尺寸、颜色、外形等。
    4、根据计算后的布局信息,调用浏览器的UI引擎进行渲染。
    而操作dom会产生几种动作,极大的影响渲染的效率。其中layout(布局)和paint(绘制)是最大的。
    1、layout就是布局变动造成重新计算(耗CPU,有时也很耗内存)。
    2、paint就是调用浏览器UI引擎进行渲染展示页面(耗cpu和内存)。
    虚拟DOM
    1、虚拟DOM不会进行排版与重绘操作。
    2、虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分,最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘,减少过多DOM节点排版与重绘损耗。
    3、真实DOM频繁排版与重绘的效率是相当低的。
    4、虚拟DOM有效降低大面积(真实DOM节点)的重绘与排版,因为最终与真实DOM比较差异,可以只渲染局部。)
    ④ 网页中元素过多对网页的加载和脚本的执行都是沉重的负担,因此要减少DOM元素的数量。
  1. 脚本执行阶段
    ① 事件委托
    采用事件委托机制,在父级元素上添加一个事件监听,来替代在每一个子元素上添加事件监听。
    ② 避免无谓的循环,break、continue、return的适当使用
    break:跳出所在的当前整个循环,到外层代码继续执行。break不仅可以结束其所在的循环,还可结束其外层循环,但一次只能结束一种循环。
    continue:跳出本次循环,从下一个迭代继续运行循环,内层循环执行完毕,外层代码继续运行。
    return:直接返回函数,return同时结束其所在的循环和其外层循环,最多只能返回一个值!
    小总结
    break; 可用作于switch和循环
    continue; 只可用作于循环
    return表达式; 只可用作于函数

七、谈谈你对vuex的理解

vuex五大核心属性:state,getter,mutation,action,module
state:存储数据,存储状态;在根实例中注册了store 后,用 this.$store.state 来访问;对应vue里面的data;存放数据方式为响应式,vue组件从store中读取数据,如数据发生变化,组件也会对应的更新。
getters:可以认为是 store 的计算属性,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
action:包含任意异步操作,通过提交 mutation 间接更变状态。
module:将 store 分割成模块,每个模块都具有statemutation、action、getter、甚至是嵌套子模块。

八、HTML5新特性

HTML是超文本标记语言,
2.语义化标签 header. footer. section
前端面试(真题重现,确定不进来看看?)_第7张图片

3.增强型表单
input输入框增加了多个输入类型。比如新增:color.,date等
前端面试(真题重现,确定不进来看看?)_第8张图片

4.新增视频和音频标签video和audio
5.新增canvas绘图
6.地理定位Geolocation
7.拖放api.
8.web store
9.脚本和链接无需type
10.语义化的HeaderFooter
语义化:明白每个标签的用途即直观的人是标签和属性的用途和作用。
好处:
①去掉样式能让页面结构呈现清晰
②屏幕阅读器会按标记“读”你的网页
③有益于SEO,SEO就是搜索引擎优化
④便于团队开发和维护

九、数组API的方法

数组的删除添加
1.pop() 方法用于删除数组的最后一个元素并返回删除的元素。
注意:此方法改变数组的长度
2.shift() 方法
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
3.push() 方法
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
4.unshift() 方法
unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。

set方法去重
1.多个数组去重 返回不同数据展示

let a = [1, 2, 3, 4]
let b = [3, 4, 5]
let union = [...new Set([...a, ...b])]
console.log(union)

2.单个数组的去重

var arr [0,2,3,4,4,0,2]
var arr2= Array.fromnew Set(arr);
console.log(arr2)

set是一种新的数据结构,它可以接收一个数组或者是类数组对象,自动去重其中的重复项目,正常情况下,NaN === NaN 返回的是false,但是在set里,一样能够帮你去重,但是这里大家可以看到,set返回的是一个对象,但是我们想要的是数组啊。这回,就该轮到Array.from出场了,它的作用,就是可以把类数组对象、可迭代对象转化为数组。目前主流的浏览器,Chrome,Firfox,Opera,Safari,包括微软的Edge,都是支持的,唯独IE系列不支持。

十、margin负值之对自身的影响

【1.margin-left/margin-right负值】
  当元素不存在width属性或width:auto时,负值margin会增加元素的宽度。
  注意:这仅是在元素不存在width属性或则width属性默认时。
【2.margin-top负值】
    margin-top为负值时,不会增加宽度,但会让元素上移。
【3.margin-bottom负值】
    margin-bottom为负值时不会位移,但会减少自身供css读取的高度。

十一、事件循环

宏任务 -> 微任务 -> 渲染,然后重复

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

主线程运行的时候,会产生堆和栈。栈中的代码会调用各种外部 API。他们在任务队列中加入各种事件。只要栈中的代码执行完毕,主线程就会去读取“任务列队”,依次执行哪些事件所对应的回调函数。主线程从“任务队列”中读取事件,这个过程是循环不断的。所以叫事件循环机制。

十二、深拷贝和浅拷贝的区别

浅拷贝:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深拷贝:在计算机中开辟一块新的内存地址用于存放复制的对象。
区别:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
深拷贝的实现方法1:JSON.parse(JSON.stringify())
2.用递归去复制所有层级属性

浅拷贝的实现方法:object.assign(target,source)
Object.assign 方法只复制源对象中可枚举的属性和对象自身的属性

十三、link和@import的区别

1、从属关系区别
@import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。
2、加载顺序区别
页面被加载时,link 会同时被加载,而 @import 引用的 css 会等到页面加载结束后加载;
3、兼容性区别
link 此没有兼容性要求,而 @import IE低版本浏览器不支持。
4、DOM可控性区别
link 可以使用 js 动态引入,@import不行;

十四、v-for key的作用

1.key的主要作用就是用来提高渲染性能的!这个key属性必须是唯一的标识
2.key属性可以避免数据混乱的情况出现 (如果元素中包含了有临时数据的元素,如果不用key就会产生数据混乱)

十四、git和svn的区别

  • svn是集中式版本控制系统,git是分布式版本控制系统。
    svn就是所有人修改的都是服务器上的程序,如果有人修改了同样的部分,那就冲突了。所以呢,一般团队会约定,对于公共部分的程序,尽量标注出开发人员特有标识,又或者A从上添加,B从下添加。
    git就是开发人员创建自己的分支,这个分支就相当于将源码copy一份在本机上,之后修改的都是本地的代码,可随时拉取服务器的代码进行同步,git可创建无数分支,开发人员只需将自己修改的代码提交就可以了,这样冲突的几率会小很多。
  • svn是直接与服务器进行交互,git是将项目缓存在本地再推送到服务器。
  • svn必须在联网的情况下工作,git可不联网开发。
  • svn旨在项目管理,git旨在代码管理。
  • svn适用于多项目并行开发,git适用于单项目开发。
  • svn适用于企业内部,由项目经理协调多个项目统筹开发,git适用于通过网络多人开发同一项目。
  • GIT的内容完整性要优于SVN
    GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏

十五、数组遍历的方法

  1. forEach 循环
    遍历数组中的每一项,没有返回值,对原数组没有影响,但不支持IE
arr.forEach((value, index, array) => {
	// 参数一是: 数组元素
	// 参数二是: 数组元素的索引
	// 参数三是:当前的数组
})

2.filter 数组过滤
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组。
注意:它不会改变原始数组,但是直接返回一个新数组。

let arr = [12, 66, 4, 88, 3, 7];
let res = arr.filter((value, index, array) => {
	// 参数一是:数组元素
	// 参数二是:数组元素的索引
	// 参数三是:当前的数组
	return value >= 20;
});
console.log(res); // [66,88] 返回值是一个新数组

3.map 循环
map的回调函数中支持return返回值,相当于把数组中的每一项改变,但并不影响原来的数组,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了

let arr = [12,23,24,42,1]; 
let res = arr.map((item, index, arr) => { 
    return item*10; 
}) 
console.log(res); // [120,230,240,420,10];  原数组拷贝了一份,并进行了修改
console.log(arr); // [12,23,24,42,1];  原数组并未发生变化
var arr1 = [1, 2, 3, 4, 5, 6]
    arr2 = arr1.map((item, index) => {
        console.log(item);//分别输出1,2,3,4,5,6
        console.log(index);//分别输出0,1,2,3,4,5
        return item * item
    })
    console.log(arr2);//[1,4,9,16,25,36]

4.some 循环
some() 是查找数组中是否有满足条件的元素,返回值是布尔值,如果查找到这个元素,就返回 true(有任意一项符合条件即返回true) , 如果查找不到就返回 false。
如果查询数组中唯一的元素,用 some 方法更合适,在 some 里面遇到 return true 就是终止遍历,迭代效率更高。

let arr = [10, 30, 4];
let flag = arr.some((value, index, array) => {
	return value < 3;
});
console.log(flag); // false 返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环

5.every 循环
every()是对数组中的每一项运行给定函数,只有当该函数对每一项返回true,才返回true,否则返回false。

let arr = [1, 2, 3, 4, 5, 6];
let flag = arr.every((value, index, array) => {
	return value > 3;
});
console.log(flag); // false

6.for of 循环
for-of 循环是ES6新增特性,for-of 的功能不仅仅用于遍历数组,它还可以 遍历字符串、遍历类数组对象、支持 Map 和 Set 对象遍历

let arr = [1, 2, 3, 4];
for (let item in arr) {
    console.log(item) // 遍历每个元素 1 2 3 4
}

十六、Promise

  • 概述:Promise是异步编程的一种解决方案,Promise是一个对象,可以获取异步操作的消息
  • 目的: (1)、避免回调地狱的问题(2)、Promise对象提供了简洁的API,使得控制异步操作更加容易 (3)、避免了层层嵌套的回调函数
  • 缺点:①无法取消promise ②当处于pending状态时,无法得知目前进展到哪一个阶段
  • Promise有三种状态:pendding //正在请求,rejected //失败,resolved //成功
  • 基础用法:new Promise(function(resolve,reject){ })
  • resolved,rejected函数:在异步事件状态pendding->resolved回调成功时,通过调用resolved函数返回结果;当异步操作失败时,回调用rejected函数显示错误信息
  • then的用法:then中传了两个参数,第一个对应resolve的回调,第二个对应reject的回调
  • catch方法:捕捉promise错误函数,和then函数参数中rejected作用一样,处理错误,由于Promise抛出错误具有冒泡性质,能够不断传递,会传到catch中,所以一般来说所有错误处理放在catch中,then中只处理成功的,同时catch还会捕捉resolved中抛出的异常

十七、Promise的构造函数是同步执行的,then中的方法是异步执行的,promise是微任务,setTimeout是宏任务,promise.then总是先与setTiemout执行

十七、水平居中和垂直居中

讲解水平居中详细方式

水平居中方式:

块级元素
方案一:(分宽度定不定两种情况)
定宽度:需要谁居中,给其设置 margin: 0 auto; (作用:使盒子自己居中)
不定宽度:默认子元素的宽度和父元素一样,这时需要设置子元素为display: inline-block; 或 display: inline;即将其转换成行内块级/行内元素,给父元素设置 text-align: center;

方案二:使用定位属性
首先设置父元素为相对定位,再设置子元素为绝对定位,设置子元素的left:50%,即让子元素的左上角水平居中;
定宽度:设置绝对子元素的 margin-left: -元素宽度的一半px; 或者设置transform: translateX(-50%);
不定宽度:利用css3新增属性transform: translateX(-50%);

方案三:使用flexbox布局实现(宽度定不定都可以)
使用flexbox布局,只需要给待处理的块状元素的父元素添加属性 display: flex; justify-content: center;

垂直居中方式

已知高度和宽度的元素

方案一:设置父元素为相对定位,给子元素设置绝对定位,top: 0; right: 0; bottom: 0; left: 0; margin: auto;
方案二:设置父元素为相对定位,给子元素设置绝对定位,left: 50%; top: 50%; margin-left: --元素宽度的一半px; margin-top: --元素高度的一半px;

未知高度和宽度的元素

1.设置父元素为相对定位,给子元素设置绝对定位,left: 50%; top: 50%; transform: translateX(-50%) translateY(-50%);
2.设置父元素为flex定位,justify-content: center; align-items: center;

十八、oninput 事件- 输入提示

oninput 事件在用户输入时触发。
该事件在