Group1

Q1:说一说cookie sessionStorage localStorage 区别?

1
2
3
4
5
6
A1:共同点:都是浏览器存储,都存储在浏览器本地 
区别: 1.cookie由服务器写入,sessionStorage以及localStorage都是由前端写入
2.cookie的生命周期由服务器端写入时就设置好的,localStorage是写入就一直存在,除非手动清除,sessionStorage是由页面关闭时自动清除
3.cookie存储空间大小约4kb,sessionStorage及localStorage空间比较大,大约5M
4.三者的数据共享都遵循同源原则,sessionStorage还限制必须是同一个页面
5.cookie一般存储登录验证信息或者token,localStorage常用于存储不易变动的数据,减轻服务器压力,sessionStorage可以用来监测用户是否是刷新进入页面,如音乐播放器恢复进度条功能

Q2:JS数据类型有哪些,区别是什么?

1
2
3
4
A2:JS数据类型分为两类:一类是基本数据类型,也叫简单数据类型,包含7种类型,分别是Number 、String、Boolean、BigInt、Symbol、Null、Undefined。另一类是引用数据类型也叫复杂数据类型,通常用Object代表,普通对象,数组,正则,日期,Math数学函数都属于Object。
基本类型存储在栈中,空间小,操作频繁;引用类型存储在堆中,空间大,在栈中存储了指针, 指向在堆中的起始地址。
加分回答:Symbol是ES6新出的一种数据类型,这种数据类型的特点就是没有重复的数据,使用getOwmPropertySymbol获取,可以作为object的key。
BigInt也是ES6新出的一种数据类型,这种数据类型的特点就是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题。

Q3:说一说你对闭包的理解?

1
2
3
4
5
A3:内层函数引用外层函数中变量,这些变量的集合就是闭包。
原理:通过作用域链,当前作用域可以访问上级作用域中的变量。
解决的问题:保存变量实现了属性私有化,防止对全局变量的污染。
带来的问题:闭包会常驻内存中,造成内存泄露。
应用:防抖节流。

Q4:说一说promise是什么与使用方法?

1
2
3
4
A4:是ES6提供的一个构造函数,异步编程的一种解决方案,用来封装异步操作并获取其成功或失败的结果。
支持链式回调,解决地狱回调(回调函数嵌套回调函数,多层嵌套)问题。
使用方法:new Promise((resolve,reject) => { resolve(); reject(); }),创建实例、.then捕捉上层状态并执行对应逻辑、catch捕获错误。 then和catch最后也是返回promise对象,所以可以链式调用。
promise有三种状态,pending,resolve,reject。promise可以由new Promise()生成,接受一个函数为参数,这个函数有两个参数,一个是resolve,一个是reject,这两个参数用来改变promise的状态。

Q5:说一说跨域是什么?如何解决跨域问题?

1
2
3
4
5
6
7
8
A5:跨域:当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了。
跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略。
跨域解决方案:1.cors:通过设置后端允许跨域实现。
2.node中间件和nginx反向代理:让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。
3.JSONP:利用的原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript。
4.postmessage:H5新增API,通过发送和接收API实现跨域通信。
5.Vue框架配置代理:vue项目的devServer设置proxy。
跨域场景:前后端分离式开发、调用第三方接口。

Q6:说一说BFC?

1
2
3
4
5
6
A6:BFC(Block Formatting Context)块级格式化上下文,是Web页面一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素。 
BFC形成的条件:1. float设置成 left或right;
2.position是absolute或者fixed;
3.overflow不是visible,为auto、scroll、hidden;
4.display是flex或者inline-block 等。
BFC解决能的问题:清除浮动。BFC的方式都能清除浮动,但是常使用的清除浮动的BFC方式只有overflow:hidden,原因是使用float或者position方式清除浮动,虽然父级盒子内部浮动被清除了,但是父级本身又脱离文档流了,会对父级后面的兄弟盒子的布局造成影响。如果设置父级为display:flex,内部的浮动就会失效。所以通常只是用overflow: hidden清除浮动。

Q7:说一说Vuex是什么,每个属性是干嘛的,如何使用 ?

1
2
3
4
5
6
7
8
9
A7:Vuex是集中管理项目公共数据的。
Vuex 有(am msg)actions,mutations,module,state,getters属性。
action:处理异步事件,事件触发Ajax请求,通过$store.dispatch调用actions中的方法 ;
mutation:处理同步事件,修改state,用$store.commit来调用mutations中的同步方法 ;
modules:模块;
state:储存数据,通过$store.state调用数据;
getters:过滤数据,计算属性,通过$store.getters调用属性。
加分回答:可以使用mapState、mapMutations、mapAction、mapGetters一次性获取每个属性下对应的多个方法。
VueX在大型项目中比较常用,非关系组件传递数据比较方便。

Q8:说一说JavaScript有几种方法判断变量的类型?

1
2
3
4
5
A8:JavaScript有4种方法判断变量的类型,分别是typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型) 。
typeof:常用于判断基本数据类型,对于引用数据类型除了function返回'function',其余全部返回'object'。
instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。
constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
Object.prototype.toString.call():适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。

Q9:说一说样式优先级的规则是什么?

1
2
3
4
5
6
7
8
A9:CSS样式的优先级应该分成四大类。
第一类:!important,无论引入方式是什么,选择器是什么,它的优先级都是最高的。
第二类:引入方式,行内样式的优先级要高于嵌入和外链,嵌入和外链如果使用的选择器相同就看他们在页面中插入的顺序,在后面插入的会覆盖前面的。
第三类:选择器,选择器优先级:id选择器>(类选择器 | 伪类选择器 | 属性选择器 )> (后代选择器 | 伪元素选择器 )> (子选择器 | 相邻选择器) > 通配符选择器 。
第四类:继承样式,是所有样式中优先级比较低的。
第五类:浏览器默认样式优先级最低。
!important > 内联样式(style) > ID选择器(id) > 类选择器(class) > 标签选择器 > 通配符
加分回答:一定要优先考虑使用样式规则的优先级来解决问题而不是 !important。

Q10:说一说JS实现异步的方法?

1
2
3
4
5
6
A10:所有异步任务都是在同步任务执行结束之后,从任务队列中依次取出执行。
1.回调函数:异步操作最基本的方法,比如AJAX回调。优点是简单、容易实现;缺点是高度耦合,不易维护。
2.Promise包装了一个异步调用并生成一个Promise实例,当异步调用返回的时候根据调用的结果分别调用实例化时传入的resolve 和 reject方法,then接收到对应的数据,做出相应的处理。Promise不仅能够捕获错误,而且也很好地解决了回调地狱的问题,缺点是无法取消 Promise,错误需要通过回调函数捕获。
3.Generator 函数是 ES6 提供的一种异步编程解决方案,封装了多个内部状态,yield可暂停,next方法可启动。
4.async/await是基于Promise实现的,async/await使得异步代码看起来像同步代码。
5.定时器setTimeout。

Q11:说一说Vue2.0 双向绑定的原理与缺陷?

1
2
A11:vue的双向绑定是采用数据劫持结合发布者订阅者模式的方式来实现响应式,通过Object.defineProperty来劫持数据的getter,setter,在数据变化时发送消息给订阅者,订阅者收到消息后进行相应的处理。
缺点是不能监听新对象的新增属性和删除属性,不能监听通过下标改变数组对应数据。

Q12:说一说数组去重都有哪些方法?

1
2
3
4
A12:第一种方法:利用对象属性key排除重复项。遍历数组,每次判断对象中是否存在该属性,不存在就存储在新数组中,并且把数组元素作为key,设置一个值,存储在对象中,最后返回新数组。
第二种方法:利用Set类型数据无重复项:let array = [...new Set(arr)] 。
第三种方法:filter+indexof 去重:arr5.filter((item, index, self) => {return self.indexOf(item) === index})。
第四种方法:使用reduce+includes:return arr.reduce((prev,curr) => prev.includes(curr) ? prev : [...prev,curr],[])。

Q13:说一说null 和 undefined 的区别,如何让一个属性变为null?

1
2
3
4
A13:null表示一个值被定义了,但是是空值,但是undefined表示未被定义,undefind 是全局对象的一个属性。
null和undefined在if判断中都会被解析为false,但是在用Number运算时,null的结果为0,undefined的结果为NaN,让属性变为null就需要先定义,再赋空值。
undefined == null
undefined !== null

Q14:说一下浮动?

1
2
A14:浮动的作用:设置了浮动的块级元素可以排列在同一行,设置了浮动的行内元素可以设置宽高,同时可以按照浮动设置的方向对齐排列盒子。会脱离文档流,悬浮在未浮动的盒子上面,同时能开启BFC但是会造成高度塌陷,影响其他元素排版。
清除浮动的方法:1.给浮动元素父级增加after伪元素{ content: ''; display: table; clear: both; } 。2.给浮动元素父级增加`overflow:hidden`。

Q15:说一说es6中箭头函数?

1
A15:1.写法简洁,省去了function关键字,使用=>来定义函数;2.不能new;3.无自己的this,继承上一个作用域的this;4.不能作为构造函数;5.没有自己的prototype;6.没有arguments对象。

Q16:说一说call apply bind的作用和区别?

1
2
3
4
A16:call apply bind三个方法都可以用来改变函数的this指向。
1.fn.call (newThis,params) call函数的第一个参数是this的新指向,后面依次传入函数fn要用到的参数。会立即执行fn函数。call用于对象的继承、伪数组转换成真数组。
2.fn.apply (newThis,paramsArr) apply函数的第一个参数是this的新指向,第二个参数是fn要用到的参数数组,会立即执行fn函数。apply用于找出数组中的最大值和最小值以及数组合并。
3.fn.bind (newThis,params) bind函数的第一个参数是this的新指向,后面的参数可以直接传递,也可以按数组的形式传入。 不会立即执行fn函数,且只能改变一次fn函数的指向,后续再用bind更改无效。bind用于vue或者react框架中改变函数的this指向。

Q17:说一说HTML语义化?

1
2
A17:HTML语义化就是指在使用HTML标签构建页面时,避免大篇幅的使用无语义的标签,要求尽可能的使用具有语义的标签,比如<header>、<footer>等。
作用:1.易于用户阅读,样式文件未加载时,页面结构清晰。2.有利于SEO。3.有利于开发和维护,代码更具可读性。

Q18:说一说this指向(普通函数、箭头函数)?

1
2
3
4
A18:this关键字由来:在对象内部的方法中使用对象内部的属性。this存在的场景有三种:全局执行上下文、函数执行上下文、eval执行上下文。
在全局环境中调用一个函数,函数内部的 this 指向的是全局变量 window。
通过一个对象来调用其内部的一个方法,该方法的执行上下文中的 this 指向对象本身。
普通函数this指向:当函数被正常调用时,在严格模式下,this 值是 undefined,非严格模式下 this 指向的是全局对象 window。

Q19:说一说CSS尺寸设置的单位?

1
2
3
4
5
A19:px:pixel像素的缩写,绝对长度单位,它的大小取决于屏幕的分辨率,是开发网页中常常使用的单位。 
vw:相对长度单位,相对于视窗宽度的1%。
vh:相对长度单位,相对于视窗高度的1%。
em:相对长度单位,在 font-size 中使用是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如 width。
rem:相对长度单位,相对于根元素的字体大小,根元素字体大小未设置,使用浏览器默认字体大小。

Q20:说几个未知宽高元素水平垂直居中方法?

1
2
3
4
A20:1. 设置元素相对父级定位position:absolute;left:50%;right:50%,让自身平移自身高度50%  transform: translate(-50%,-50%);,这种方式兼容性好,被广泛使用的一种方式;
2. 设置元素的父级为弹性盒子display:flex,设置父级和盒子内部子元素水平垂直都居中justify-content:center; align-items:center ;
3. 设置元素的父级为网格元素display: grid,设置父级和盒子内部子元素水平垂直都居中justify-content:center; align-items:center;
4. 设置元素的父级为表格元素display: table-cell,其内部元素水平垂直都居中text-align: center;vertical-align: middle; ,设置子元素为行内块display: inline-block; ,这种方式兼容性较好。

Q21:说一说JS变量提升?

1
2
3
4
A21:变量提升是指JS的变量和函数声明会在代码编译期,提升到代码的最前面。
变量提升成立的前提是使用Var关键字进行声明的变量,并且变量提升的时候只有声明被提升,赋值并不会被提升,同时函数的声明提升会比变量的提升优先。
变量提升的结果,可以在变量初始化之前访问该变量,返回的是undefined。在函数声明前可以调用该函数。
使用let和const声明的变量是创建提升,形成暂时性死区,不能提前访问和调用,变量不会存在变量提升问题。

Q22:说一说 HashRouter 和 HistoryRouter的区别和原理?

1
2
3
4
5
A22:区别: 1. history和hash都是利用浏览器的两种特性实现前端路由,history是利用浏览历史记录栈的API实现,hash是监听location对象hash值变化事件来实现;
2. history的url没有'#'号,hash反之;
3. 相同的url,history会触发添加到浏览器历史记录栈中,hash不会触发,history需要后端配合,如果后端不配合刷新新页面会出现404,hash不需要。
HashRouter的原理:通过 window.onhashchange 方法获取新URL中hash值,再做进一步处理。
HistoryRouter的原理:通过history.pushState使用它做页面跳转不会触发页面刷新,使用window.onpopstate监听浏览器的前进和后退,再做其他处理。

Q23:说一说map 和 forEach 的区别?

1
2
3
4
A23:区别:map有返回值,可以开辟新空间,return出来一个length和原数组一致的数组,即便数组元素是undefined或者是null。forEach默认无返回值,返回结果为undefined,可以通过在函数体内部使用索引修改数组元素。 
map的处理速度比forEach快,而且返回一个新的数组,方便链式调用其他数组新方法,比如filter、reduce。
let arr = [1, 2, 3, 4, 5];
let arr2 = arr.map(value => value * value).filter(value => value > 10); // arr2 = [16, 25]

Q24:说一说事件循环Event loop,宏任务与微任务?

1
2
3
4
5
6
A24:浏览器的事件循环:执行js代码的时候,遇见同步任务,直接推入调用栈中执行,遇到异步任务,将该任务挂起,等到异步任务有返回之后推入到任务队列中,当调用栈中的所有同步任务全部执行完成,将任务队列中的任务按顺序一个一个的推入并执行,重复执行这一系列的行为。
异步任务又分为宏任务和微任务。
宏任务:任务队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列。
微任务:等宏任务中的主要功能都完成后,渲染引擎不急着去执行下一个宏任务,而是执行当前宏任务中的微任务。
宏任务包含:执行script标签内部代码、setTimeout/setInterval、ajax请求、postMessageMessageChannel、setImmediate,I/O(Node.js)。
微任务包含:Promise、MutonObserver、Object.observe、process.nextTick(Node.js)。

Q25:说一说Vue3.0 实现数据双向绑定的方法 ?

1
2
3
A25:在Vue2.0的基础上将Object.definedproperty换成了功能更强大的proxy,Vue3.0 是通过Proxy实现的数据双向绑定,Proxy是ES6中新增的一个特性,实现的过程是在目标对象之前设置了一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
var proxy = new Proxy(target, handler);
相对vue2.0解决的问题:解决无法监听新增属性或删除属性的响应式问题、解决无法监听数组长度和index变化问题。

Q26:说一下Diff算法?

1
2
A26:Diff算法主要就是在虚拟DOM树发生变化后,生成DOM树更新补丁的方式,对比新旧两株虚拟DOM树的变更差异,将更新补丁作用于真实DOM,以最小成本完成视图更新。
框架会将所有的结点先转化为虚拟节点Vnode,在发生更改后将VNode和原本页面的OldNode进行对比,然后以VNode为基准,在oldNode上进行准确的修改。

Q27:说一说三栏布局的实现方案?

1
2
3
4
A27:三栏布局,要求左右两边盒子宽度固定,中间盒子宽度自适应,盒子的高度都是随内容撑高的,一般都是中间盒子内容较多,为了保证页面渲染快,在写结构的时候,需要把中间盒子放在左右盒子的前面。
实现三栏布局的方法通常是圣杯布局和双飞翼布局。
圣杯布局,顾名思义,中间容器高,旁边两侧的容器低,整个布局看上去像一个圣杯。圣杯布局的实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右padding,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置margin,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="father">
<div class="middle">
圣杯布局的实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右`padding`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开 双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动,设置中间盒子宽度100%
圣杯布局的实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右`padding`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开 双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动,设置中间盒子宽度100%
圣杯布局的实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右`padding`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开 双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动,设置中间盒子宽度100%
</div>
<div class="left">
圣杯布局的实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右`padding`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度
</div>
<div class="right">
圣杯布局的实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右`padding`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.father{
width:700px;
height:500px;
position:relative;
padding-left:150px;
padding-right:200px;
}
.father div{
height:fit-content;/*或固定*/
float:left;
}
.middle{
width:100%;
}
.left{
width:150px;
margin-left:-100%;
position:relative;
right:150px;
}
.right{
width:200px;
margin-left:-200px;
position:relative;
left:200px;
}

加了*{outline:1px solid red;}样式之后可以看到布局轮廓

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="father">
<div class="center">
双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动,设置中间盒子宽度100%,左右盒子设置固定宽度,设置左边盒子左边距-100%,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
</div>
</div>
<div class="left">
双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动
</div>
<div class="right">
双飞翼布局的实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置`margin`,三个盒子全部浮动。
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.father{
width:100%;/*上述html标签直接放在body下时,这里必须用100%才能实现双飞翼效果*/
}
.center{
margin-left:400px;
margin-right:500px;
float:left;
}
.left{
float:left;
width:400px;
margin-left:-100%;
}
.right{
float:left;
width:500px;
margin-left:-500px;
}

Q28:说一下浏览器垃圾回收机制?

1
2
3
4
5
6
7
浏览器垃圾回收机制根据数据的存储方式分为栈垃圾回收和堆垃圾回收。
栈垃圾回收的方式非常简便,当一个函数执行结束之后,JavaScript 引擎会通过向下移动 ESP 来销毁该函数保存在栈中的执行上下文,遵循先进后出的原则。
堆垃圾回收,当函数直接结束,栈空间处理完成了,但是堆空间的数据虽然没有被引用,但是还是存储在堆空间中,需要垃圾回收器将堆空间中的垃圾数据回收。
为了使垃圾回收达到更好的效果,根据对象的生命周期不一样,使用不同的垃圾回收的算法。在 V8(Google JavaScript引擎)中会把堆分为新生代和老生代两个区域,新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象。
Scavenge算法:1.标记:对对象区域中的垃圾进行标记;2.清除垃圾数据和整理碎片化内存:副垃圾回收器会把这些存活的对象复制到空闲区域中,并且有序的排列起来,复制后空闲区域就没有内存碎片了;3.角色翻转:完成复制后,对象区域与空闲区域进行角色翻转,也就是原来的对象区域变成空闲区域,原来的空闲区域变成了对象区域,这样就完成了垃圾对象的回收操作,同时这种角色翻转的操作还能让新生代中的这两块区域无限重复使用下去。
标记-清除算法:1.标记:标记阶段就是从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。2.清除:将垃圾数据进行清除。3. 产生内存碎片:对一块内存多次执行“标记-清除算法”后,会产生大量不连续的内存碎片。而碎片过多会导致大对象无法分配到足够的连续内存。
标记-整理算法:1.标记:和“标记-清除”的标记过程一样,从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素标记为活动对象。2.整理:让所有存活的对象都向内存的一端移动;3.清除:清理掉端边界以外的内存V8是使用副垃圾回收器和主垃圾回收器处理垃圾回收的,不过由于 JavaScript 是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。我们把这种行为叫做全停顿。为了降低老生代的垃圾回收而造成的卡顿,V8 将标记过程分为一个个的子标记过程,同时让垃圾回收标记和 JavaScript 应用逻辑交替进行,直到标记阶段完成,我们把这个算法称为增量标记(Incremental Marking)算法。

Q29:说一说 vue 的

1
2
3
4
定义:keep-alive是vue的内置组件,能在组件切换过程中将状态保留在内存中,相当于缓存,防止DOM的重复渲染。
作用:缓存组件,提升性能,避免重复加载一些不需要经常变动且内容较多的组件。
keep-alive对应两个声明周期,activated和deactivated;有三个属性,include(只有匹配的组件才会被保存),exclude(只有匹配的组件才不会被保存)和max(最多能保存的组件数)。
<keep-alive>的使用方法:使用<keep-alive>标签对需要缓存的组件进行包裹,默认情况下被<keep-alive>标签包裹的组件都会进行缓存,区分被包裹的组件是否缓存有两种方法,第一种是给<keep-alive>添加属性,组件名称指的是具体组件添加的name,不是路由里面的name。

Q30:CSRF攻击是什么?

1
2
3
4
5
6
7
8
9
10
CSRF跨站点请求伪造(Cross Site Request Forgery)和XSS攻击一样,有巨大的危害性,就是攻击者盗用了用户的身份,以用户的身份发送恶意请求,但是对服务器来说这个请求是合理的,这样就完成了攻击者的目标。
原理: - 用户打开浏览器,访问目标网站A,输入用户名和密码请求登录
- 用户信息在通过认证后,网站A产生一个cookie信息返回给浏览器,这个时候用户以可正常发送请求到网站A
- 用户在没有退出网站A之前在同一个浏览器打开了另一个新网站B。
- 新网站B收到用户请求之后返回一些攻击代码,并发出一个请求要求访问返回cookie的网站A
- 浏览器收到这些攻击性代码之后根据新网站B的请求在用户不知道的情况下以用户的权限操作了cookie并向网站A服务器发起了合法的请求。
预防CSRF攻击的策略: - 使用验证码,在表单中添加一个随机的数字或者字母验证码,强制要求用户和应用进行直接的交互。
- HTTP中Referer字段,检查是不是从正确的域名访问过来,它记录了HTTP请求的来源地址。
- 使用token验证,在HTTP请求头中添加token字段,并且在服务器端建立一个拦截器验证这个token,如果token不对,就拒绝这个请求。
使用token验证的方法要比referer更安全一些。

Q31:XSS攻击是什么?

1
2
3
4
5
XSS是跨站脚本攻击(Cross Site Scripting),不写为CSS是为了避免和层叠样式表(Cascading Style Sheets)的缩写混淆。
攻击者可以通过向目标网站插入恶意script代码,大量用户访问网站时运行恶意脚本获取信息。
XSS的危害一般是泄露用户的登录信息cookie,攻击者可以通过cookie绕过登录步骤直接进入站点。
XSS的分类分为反射型和存储型。反射型就是临时通过url访问网站,网站服务端将恶意代码从url中取出,拼接在HTML中返回给浏览器,用户就会执行恶意代码。存储型就是将恶意代码以留言的形式保存在服务器数据库,任何访问网站的人都会受到攻击。
预防XSS攻击的方案基本是对数据进行严格的输出编码,比如HTML元素的编码,JavaScript编码,css编码,url编码等等。

Q32:说一说js继承的方法和优缺点?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1.原型链继承:当一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。
优点:写法方便简洁,容易理解。
缺点:在父类型构造函数中定义的引用类型值的实例属性,会在子类型原型上变成原型属性被所有子类型实例所共享。同时在创建子类型的实例时,不能向超类型的构造函数中传递参数。
2.借用构造函数继承:在子类型构造函数的内部调用父类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上。
优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题。
缺点:借用构造函数的缺点是方法都在构造函数中定义,因此无法实现函数复用。在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。
3.组合继承:将原型链和借用构造函数的组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。
优点:解决了原型链继承和借用构造函数继承造成的影响。
缺点:无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
4.原型式继承:在一个函数A内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。本质上,函数A是对传入的对象执行了一次浅复制。ECMAScript 5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。在只有一个参数时,Object.create()与这里的函数A方法效果相同。
优点:不需要单独创建构造函数。
缺点:属性中包含的引用值始终会在相关对象间共享。
5.寄生式继承:寄生式继承背后的思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。
优点:写法简单,不需要单独创建构造函数。
缺点:通过寄生式继承给对象添加函数会导致函数难以重用。
6.寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
优点:高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要,多余的属性。与此同时,原型链还能保持不变。
缺点:代码复杂。

Q33:说一说defer和async区别?

1
2
3
4
浏览器会立即加载JS文件并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
加上async属性,加载JS文档和渲染文档可以同时进行(异步),当JS加载完成,JS代码立即执行,会阻塞HTML渲染。
加上defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),当HTML渲染完成,才会执行JS代码。
渲染阻塞的原因: 由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置 GUI 渲染线程与 JavaScript 引擎为互斥的关系。

Q34:说一下浏览器如何渲染页面的?

1
浏览器拿到HTML,先将HTML转换成dom树,再将CSS样式转换成stylesheet,根据dom树和stylesheet创建布局树,对布局树进行分层,为每个图层生成绘制列表,再将图层分成图块,紧接着光栅化将图块转换成位图,最后合成绘制生成页面。

Q35:说一说computed和watch的区别?

1
2
computed:计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算。
watch:更多的是观察的作用,支持异步,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。

Q36:说一说 Vue 中 $nextTick 作用与原理?

1
2
3
Vue 在更新 DOM 时是异步执行的,在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取DOM,获取的仍然是未修改的DOM。
$nextTick的作用是:该方法中的代码会在当前渲染完成后执行,就解决了异步渲染获取不到更新后DOM的问题了。
$nextTick的原理:$nextTick本质是返回一个Promise。

Q37:说一说new会发生什么?

1
2
1.创建一个空的简单JavaScript对象(即{}); 2.为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象; 3.将步骤1新创建的对象作为this的上下文; 4.如果该函数没有返回对象,则返回this。
new关键字后面的构造函数不能是箭头函数。

Q38:说一下token 能放在cookie中吗?

1
2
3
能。
token一般是用来判断用户是否登录的,它内部包含的信息有:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)。
token可以存放在Cookie中,token是否过期,应该由后端来判断,不该前端来判断,所以token存储在cookie中只要不设置cookie的过期时间就ok了,如果token失效,就让后端在接口中返回固定的状态表示token失效,需要重新登录,再重新登录的时候,重新设置cookie中的token就行。

Q39:说一下浏览器输入URL发生了什么?

1
2
3
4
5
6
7
8
9
1. url解析:判断是搜索内容还是请求URL 
2. 查找本地缓存:如果有缓存直接返回给页面,没有缓存则进入网络请求阶段
3. DNS解析
4. 通过三次握手建立TCP连接
5. 合成请求头信息,发送http请求
6. 处理响应信息
7. 通过四次挥手断开TCP连接
8. 如果响应状态码301,则重定向
9. 浏览器进行页面渲染:1)解析html,生成DOM树;2)根据css计算节点样式,生成stylesheet;3)生成布局树;4)为特定的元素生成独立图层;5)...

Q40:说一说组件通信的方式?

1
2
3
4
5
Vue组件的通信方式分为两大类,一类是父子组件通信,另一类是任何关系类型组件通信(父子、兄弟、非兄弟)。
父子:props,emit,refs
兄弟:eventbus,emit
隔代:inject,provide,attr,listener
复杂关系:vuex,pinia

Q41:说一说 v-if 和 v-show区别?

1
2
v-show: 控制的元素无论是true还是false,都被渲染出来了,通过display:none控制元素隐藏,适合使用在切换频繁显示/隐藏的元素上。
v-if: 控制的元素是true,进行渲染,如果是false不渲染,根本在dom树结构中不显示,适合使用在切换不频繁,且元素内容很多,渲染一次性能消耗很大的元素上。

Q42:说一说盒模型?

1
2
3
4
5
6
CSS盒模型定义了盒的每个部分包含 margin, border, padding, content。
根据盒子大小的计算方式不同盒模型分成了两种,标准盒模型和怪异盒模型。
标准模型:给盒设置width和height,实际设置的是content box。padding和border再加上设置的宽高一起决定整个盒子的大小。
怪异盒模型:给盒设置width和height,包含了padding和border,设置的width和height就是盒子实际的大小。
默认情况下,盒模型都是标准盒模型。
设置标准盒模型:box-sizing:content-box;设置怪异盒模型:box-sizing:border-box。

Q43:说一说伪数组和数组的区别?

1
2
3
4
伪数组它的类型不是Array,而是Object,而数组类型是Array。
伪数组可以使用的length属性查看长度,也可以使用[index]获取某个元素,但是不能使用数组的其他方法,也不能改变长度,遍历使用for in方法。
伪数组的常见场景:1.函数的参数arguments;2.原生js获取DOM:document.querySelector('div') 等;3.jquery获取DOM:$(“div”)等。
伪数组转换成真数组方法:1.Array.prototype.slice.call(伪数组);2.[].slice.call(伪数组);3.Array.from(伪数组)。转换后的数组长度由length属性决定。索引不连续时转换结果是连续的,会自动补位。

Q44:说一说如何实现可过期的localstorage数据?

1
2
3
localStorage只能用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。所以要实现可过期的localStorage缓存的中重点就是:如何清理过期的缓存。
目前有两种方法,一种是惰性删除,另一种是定时删除。
惰性删除是指某个键值过期后,该键值不会被马上删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。实现方法是,存储的数据类型是个对象,该对象有两个key,一个是要存储的value值,另一个是当前时间。获取数据的时候,拿到存储的时间和当前时间做对比,如果超过过期时间就清除Cookie。

Q45:说一说axios的拦截器原理及应用?

1
2
3
4
axios为开发者提供了这样一个API:拦截器。拦截器分为 请求(request)拦截器和 响应(response)拦截器。
请求拦截器用于在接口请求之前做的处理,比如为每个请求带上相应的参数(token,时间戳等)。
返回拦截器用于在接口返回之后做的处理,比如对返回的状态进行判断(token是否过期)。
原理:创建一个chn数组,数组中保存了拦截器相应方法以及dispatchRequest(dispatchRequest这个函数调用才会真正的开始下发请求),把请求拦截器的方法放到chn数组中dispatchRequest的前面,把响应拦截器的方法放到chn数组中dispatchRequest的后面,把请求拦截器和相应拦截器forEach将它们分unshift,push到chn数组中,为了保证它们的执行顺序,需要使用promise,以出队列的方式对chn数组中的方法挨个执行。

Q46:说一说创建ajax过程?

1
2
3
4
5
1. 创建XHR对象:new XMLHttpRequest() ;
2. 设置请求参数:request.open(Method, 服务器接口地址);
3. 发送请求: request.send(),如果是get请求不需要参数,post请求需要参数request.send(data)
4. 监听请求成功后的状态变化:根据状态码进行相应的处理。 XHR.onreadystatechange = function () { if (XHR.readyState == 4 && XHR.status == 200) { console.log(XHR.responseText); // 主动释放,JS本身也会回收的 XHR = null; } };
(readyState值说明 0:初始化,XHR对象已经创建,还未执行open 1:载入,已经调用open方法,但是还没发送请求 2:载入完成,请求已经发送完成 3:交互,可以接收到部分数据 4:数据全部返回 status值说明 200:成功 404:没有发现文件、查询或URl 500:服务器产生内部错误)

Q47:说一下fetch 请求方式?

1
2
3
fetch是一种HTTP数据请求的方式,是XMLHttpRequest的一种替代方案。Fetch函数就是原生js,没有使用XMLHttpRequest对象。fetch()方法返回一个Promise解析Response来自Request显示状态(成功与否)的方法。
XMLHttpRequest的问题:1.所有的功能全部集中在一个对象上, 容易书写出混乱而且不容易维护的代码;2.采用传统的事件驱动模式, 无法适配新的 Promise API。
Fetch API的特点:1.精细的功能分割: 头部信息, 请求信息, 响应信息等均分布到不同的对象, 更利于处理各种复杂的数据交互场景;2.使用Promise API, 更利于异步代码的书写;3.同源请求也可以自定义不带 cookie,某些服务不需要 cookie 场景下能少些流量。

Q48:说一下有什么方法可以保持前后端实时通信?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1.轮询:客户端和服务器之间会一直进行连接,每隔一段时间就询问一次。
优点:实现简单,无需做过多的更改。
缺点:连接数会很多,一个接受,一个发送。而且每次发送请求都会有Http的Header,会很耗流量,也会消耗CPU的利用率。轮询的间隔过长,会导致用户不能及时接收到更新的数据;轮询的间隔过短,会导致查询请求过多,增加服务器端的负担。
轮询适用于:小型应用,实时性不高。
2.长轮询:对轮询的改进版,客户端发送HTTP给服务器之后,如果没有新消息,就一直等待。有新消息,才会返回给客户端。在某种程度上减小了网络带宽和CPU利用率等问题。由于http数据包的头部数据量往往很大(通常有400多个字节),但是真正被服务器需要的数据却很少(有时只有10个字节左右),这样的数据包在网络上周期性的传输,难免对网络带宽是一种浪费。
优点是做了优化,有较好的时效性。
缺点是保持连接会消耗资源; 服务器没有返回有效数据,程序超时。
长轮询适用于:一些早期的对及时性有一些要求的应用:web,IM,聊天。
3.iframe流方式:是在页面中插入一个隐藏的iframe,利用其src属性在服务器和客户端之间创建一条长连接,服务器向iframe传输数据(通常是HTML,内有负责插入信息的javascript),来实时更新页面。
优点:消息能够实时到达;浏览器兼容好。
缺点:服务器维护一个长连接会增加开销;IE、chrome、Firefox会显示加载没有完成,图标会不停旋转。
iframe适用于:客服通信等。
4.WebSocket:类似Socket的TCP长连接的通讯模式,一旦WebSocket连接建立后,后续数据都以帧序列的形式传输。
优点:在客户端断开WebSocket连接或Server端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发和客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。
缺点:浏览器支持程度不一致,不支持断开重连。
WebSocket适用于:微信、网络互动游戏等。
5.SSE(Server-Sent Event):建立在浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息。SSE 是单向通道,只能服务器向浏览器发送,因为 streaming 本质上就是下载。
优点:SSE 使用 HTTP 协议,现有的服务器软件都支持。SSE 属于轻量级,使用简单;SSE 默认支持断线重连。
SSE适用于:金融股票数据、看板等。

Q49:说一下重绘、重排区别如何避免?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
重排:当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,所以重绘跳过了创建布局树和分层的阶段。
重排需要重新计算布局树,重绘不需要,重排必定发生重绘,但是涉及到重绘不一定要重排。涉及到重排对性能的消耗更多一些。
触发重排的方法:1.页面初始渲染,这是开销最大的一次重排;
2.添加/删除可见的DOM元素;
3.改变元素位置;
4.改变元素尺寸,比如边距、填充、边框、宽度和高度等;
5.改变元素内容,比如文字数量,图片大小等;
6.改变元素字体大小;
7.改变浏览器窗口尺寸,比如resize事件发生时;
8.激活CSS伪类(例如:`:hover`);
9.设置 style 属性的值,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow;
10.查询某些属性或调用某些计算方法:offsetWidth、offsetHeight等。
避免重排的方式:1.样式集中改变;2.使用 absolute 或 fixed 脱离文档流;3.使用GPU加速:transform。
(GPU的过程是以下这几步 : 1. 获取DOM并将其分割成多个层(renderLayer) 2. 将每个层栅格化,并独立的绘制进位图中 3. 将这些位图作为纹理上传至GPU 4. 复合多个层来生成最终的屏幕图像(最后的layer) 开启了GPU加速的元素被独立出来,不会再影响其他dom的布局,因为它改变之后,只是相当于被贴上了页面。)

Q50:说一说 Vue 列表为什么加 key?

1
为了性能优化。因为vue是虚拟DOM,更新DOM时用diff算法对节点进行一一比对,比如有很多li元素,要在某个位置插入一个li元素,但没有给li上加key,那么在进行运算的时候,就会将所有li元素重新渲染一遍,但是如果有key,那么它就会按照key一一比对li元素,只需要创建新的li元素,插入即可,不需要对其他元素进行修改和重新渲染。

Q51:说一说vue-router 实现懒加载的方法?

1
2
3
vue-router 实现懒加载的方法有两种:
1. ES6的impot方式: component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
2. VUE中的异步组件进行懒加载方式: component: resolve=>(require(['../views/About'],resolve))

Q52:说一说前端性能优化手段?

1
2
3
4
前端性能优化分为两类,一类是文件加载更快,另一类是文件渲染更快。
加载更快的方法:让传输的数据包更小(压缩文件/图片):图片压缩和文件压缩;减少网络请求的次数:雪碧图/精灵图、节流防抖;减少渲染的次数:缓存(HTTP缓存、本地缓存、Vue的keep-alive缓存等)。
渲染更快的方法:提前渲染:ssr服务器端渲染;避免渲染阻塞:CSS放在HTML的head中,JS放在HTML的body底部;避免无用渲染:懒加载;减少渲染次数:对dom查询进行缓存、将dom操作合并、使用减少重排的标签。
(雪碧图的应用场景一般是项目中不常更换的一些固定图标组合在一起,比如logo、搜索图标、切换图标等。 电商项目中最常用到的懒加载,一般在查看商品展示的时候通常下拉加载更多,因为商品数据太多,一次性请求过来数据太大且渲染的时间太长。)

Q53:说一说性能优化有哪些性能指标,如何量化?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1.Speed Index(lighthouse,速度指数)
2.TTFB(Network,第一个请求响应时间)
3.页面加载时间
4.首次渲染
5.交互动作的反馈时间
6.帧率FPS(动画 ctrl+shift+p)
7.异步请求完成时间:使用性能测量工具进行量化
8.Chrome DevTools
9.开发调试、性能评测
10.Audit(Lighthouse)
11.Throttling 调整网络吞吐
12.Performance 性能分析
13.Network 网络加载分析
14.Lighthouse
15.网站整体质量评估
16.还可以提出优化建议
17.WebPageTest
18.测试多地点(球各地的用户访问你的网站的性能情况)
19.全面性能报告(first view,repeat view,waterfall chart 等等)
20.WebPageTest 还可以进行本地安装,让你的应用在还没上线的时候就可以测试

Q54:说一说服务端渲染?

1
2
3
4
SSR是Server Side Render的简称。
页面上的内容是通过服务端渲染生成的,浏览器直接显示服务端返回的html就可以了。
和它对应的是,CSR是Client Side Render简称,客户端在请求时,服务端不做任何处理,直接将前端资源打包后生成的html返回给客户端,此时的html中无任何网页内容,需要客户端去加载执行js代码才能渲染生成页面内容,同时完成事件绑定,然后客户端再去通过ajax请求后端api获取数据更新视图。
服务端渲染的优势:减少网络传输,响应快,用户体验好,首屏渲染快,对搜索引擎友好,搜索引擎爬虫可以看到完整的程序源码,有利于SEO。

Q55:事件扩展符用过吗(…),什么场景下?

1
2
3
展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。
常见的场景:等价于apply的方式、将数组展开为构造函数的参数、字面量数组或字符串连接不需要使用concat等方法了、构造字面量对象时,进行浅克隆或者属性拷贝。
该语法只能用于 可迭代对象: var obj = {'key1': 'value1'}; var array = [...obj]; // TypeError: obj is not iterable

Q56:说一说vue钩子函数?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
钩子函数用来描述一个组件从引入到退出的全过程中的某个过程,整个过程称为生命周期。
钩子函数按照组件生命周期的过程分为,挂载阶段=>更新阶段=>销毁阶段。
挂载阶段:beforeCreate、created、beforeMounted、mounted
更新阶段:beforeUpdate、updated
销毁阶段:beforeDestroy、destroyed
created:实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到el属性,el属性,ref属性内容为空数组常用于简单的ajax请求,页面的初始化;
beforeMount:在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数;
mounted:实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问常用于获取VNode信息和操作,ajax请求;
beforeupdate:响应式数据更新时调用,发生在虚拟DOM打补丁之前,适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器;
updated:虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作避免在这个钩子函数中操作数据,可能陷入死循环;
beforeDestroy:实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例,常用于销毁定时器、解绑全局事件、销毁插件对象等操作。
父子组件钩子函数在三个阶段的代码执行顺序:
挂载:父亲created> 子created > 子mounted> 父亲mounted
更新:父亲beforeUpdate > 子beforeUpdated > 子updated > 父亲updated
销毁:父亲beforeDestroy> 子beforeDestroy > 子destroyed> 父destroyed

Group2

Q1:HTML 中 href、src 区别?

1
2
3
4
5
A1:href 是 Hypertext Reference 的缩写,表示超文本引用。常用的有:link、a。
浏览器会识别该文档为 css 文档,并行下载该文档,并且不会停止对当前文档的处理。
src 是 source 的缩写,是引入。常用的有:img、script、iframe。
src 指向的内容会嵌入到文档中当前标签所在的位置。当浏览器解析到该元素时,会暂停浏览器的渲染,直到该资源加载完毕。
src 用于替换当前元素;href 用于在当前文档和引用资源之间建立联系。

Q2:script标签在HTML页面放置的位置?

1
2
3
4
5
6
7
8
9
1.script标签放在head标签内部
浏览器解析HTML,解析到script标签时,会先下载完所有script,再往下解析其他的HTML。因此,将script标签放在头部,会使网页内容呈现滞后,用户体验差。
2.script标签放在body标签内部
将script标签放在body尾部,浏览器会先解析完整个HTML页面,再下载js,这样的话,如果js执行出错了,最起码页面中的元素还可以加载出来,因为DOM文档是从上往下的顺序执行的。 但是对于一些高度依赖于js的网页,这样就会显得很慢。
3.script标签放在body闭标签之后
从HTML 2.0起放在body闭标签之后就是不合标准的。之所以浏览器不会报错,是因为浏览器会忽略之前的</body>,即视作仍旧在body内部,所以实际效果和写在body闭合标签之前是没有区别的。

Q2.1:怎样实现边解析页面边下载js呢?
<script async src="script01.js"></script> async的设置,会使得script脚本异步的加载并在允许的情况下执行,但是并不会按照在script在页面中的顺序来执行,而是谁先加载完谁执行。