目录
1.1区别
2.js数据类型及区别
2.1js数据类型分为两类
2.2区别
3.对闭包的理解
3.1概念
3.2闭包形成的原理
3.3闭包带来的问题
3.4闭包的应用
4.promise
4.1promise的作用
4.2promise的使用
4.3promise的特点
4.4手写promise
5.跨域
5.1跨域概念
5.2跨域解决方案
5.3跨域场景
6.BFC
6.1概念
6.2布局规则
6.3形成条件
7.Vuex
7.1是什么
7.2属性的作用
7.3如何使用
8.js有几种方法判断变量的类型
9.CSS样式优先级规则
10.js实现异步的方法
11.Vue2.0双向绑定原理与缺陷
12.数组去重的方法
13.null和undefined的区别,如何让一个属性变为null
14.CSS的浮动
15.es6箭头函数
16.call、apply、bind的作用和区别
17、this指向(普通函数、箭头函数)
18.CSS尺寸设置的单位
19.元素水平垂直居中的方法
20.js变量提升
21.HashRouter和HistoryRouter的区别和原理
22.map和forEach的区别
23.事件循环Event loop,宏任务与微任务
24.Vue3.0实现数据双向绑定的方法
25.Diff算法
26.三栏布局的实现方案
27.浏览器垃圾回收机制
28.Vue的keep-alive
29.CSRF攻击是什么
30.XSS攻击是什么
31.js继承的方法和优缺点
32.defer和async的区别
33.浏览器如何渲染页面的
34.computed和watch的区别和运用场景
35.Vue中$nextTick的作用与原理
36.new一下会发生什么
38.浏览器输入URL发生了什么
39.Vue组件通信的方式
40.v-if和v-show的区别
41.什么是MVVM
42.对SPA单页面的理解它的优缺点是什么
43.什么是盒子模型
44.怎样理解Vue的单项数据流
45.Vue的父组件和子组件生命周期
一类是基本数据类型,也叫简单数据类型,包含7种分别是:Number、String、Boolean、null、undefined、BigInt、Symbol(Symbol和BigInt是ES6新出的数据类型,其中BigInt的特点是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题;Symbol的特点是没有重复的数据,可以作为object的key)。
一类是引用数据类型,也叫复杂数据类型,通常用Object代表,像我们经常用的对象、函数、数组、正则、日期等都属于Object。
本质上的区别是它们在内存中的存储方式不同。基本数据类型是直接存储在栈中,属于被频繁使用的数据;引用数据类型是存在在堆内存中,在栈里面存储了指针,该指针指向堆内存中该实体的一个起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得该实体。
一个函数对周围状态的引用捆绑在一起,内层函数可以访问到其外层函数的作用域,外层函数也可以访问到内层函数的作用域。
相当于一个作用域链,当前作用域可以访问上级作用域中的变量
由于垃圾回收器不会将闭包中的变量销毁,于是就造成了内存泄漏,内存泄漏积累多了容易导致内存溢出。
内存泄漏(memory leak): 是指程序在申请内存后,无法释放已申请的内存空间,导致系统无法及时回收内存并且分配给其他进程使用。
内存溢出(out of memory):指程序申请内存时,没有足够的内存供申请者使用,导致数据无法正常存储到内存中。
能够模仿块级作用域,实现数据的一个私有化。
promise是异步微任务,解决了异步多层嵌套回调的问题,让代码的可读性更高,更容易维护。
promise是ES6提供的一个构造函数,可以使用promise构造函数new一个实例,promise构造函数接收一个函数作为参数,这个函数有两个参数,分别是 ‘resolve’ 和 ‘reject’,resolve将promise的状态由等待变为成功,将异步操作的结果作为参数传递过去;reject则将状态由等待转变为失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。实例创建完成后,可以使用 ‘then’ 方法分别指定成功或失败的回调函数,也可以使用catch捕获失败,then和catch最终返回的也是一个promise。所以可以链式调用。
//执行器函数先执行(同步任务),再new Promise(),启动异步任务
const p = new Promise((resolve, reject) => {
//异步函数
setTimeout(() => {
if(Date.now()%2 == 0) {
resolve('成功')
} else {
reject('失败')
}
}, 1000);
})
p.then(
//这里的value是从异步函数中获取到的成功的返回值
(value) => {
console.log(value);
},
//这里的reason是从异步函数中获取到的失败的原因
(reason) => {
console.log(reason)
}
)
当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了
前后端分离式开发、调用第三方接口
BFC(Block Formatting Context)块级格式化上下文,是Web页面一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素。
BFC的方式都能清楚浮动,但是常用的清除浮动的BFC方式只有overflow:hidden,因为使用float或者position方式清除浮动,虽然父级盒子内部浮动被清除了,但是父级本身脱离了文档流,会对父级后面的兄弟盒子的布局造成影响。如果设置父级为display:flex,内部的浮动就会失效。所以通常只是用overflow:hidden清除浮动
Vuex是集中管理项目公共数据的。
state:直接以对象方式添加属性
mutations:通过store.commit调用
action:通过store.dispatch方法触发
getters:直接通过store.getters调用
可以使用mapState、mapMutations、mapAction、mapGetters一次性获取每个属性下对应的多个方法。Vuex在大型项目中比较常用,非关系组件传递数据比较方便
instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链_proto_上,只要在它的原型链上,则结果都为true。因此,instanceof在查找的过程中会遍历左边变量的原型链,直到找到右边变量的prototype,找到返回true,未找到返回false
Object.prototype.toString.call()实现原理:Object.prototype.toString表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()指向不同的数据类型上面,返回不同的结果
第一类是!important,不管引入方式是什么,选择器是什么,它的优先级都是最高的
第二类是引入方式的不同,优先级也会不同,行内样式的优先级是高于内部样式和外部样式的,如果两者使用的选择器是相同的,就看他们在页面中插入的顺序,后面的会覆盖前面的
第三类就是选择器,选择器的优先级是:id选择器 > (类选择器 | 伪类选择器 | 属性选择器) > (后代选择器 | 伪元素选择器) > (子选择器 | 相邻选择器) > 通配符选择器
第四类就是继承样式,是所有样式中优先级比较低的
第五类是浏览器默认的样式优先级是最低的
所有的异步任务都是在同步任务执行结束后,从任务队列中依次取出执行,回调函数是异步操作最基本的方法,比如ajax回调,回调函数的优点是简单、容易理解和实现,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,使得程序结构混乱、流程难以追踪(尤其是多个回调函数嵌套的情况),而且每个任务只能指定一个回调函数。此外,它不能使用try catch 捕获错误,不能直接return promise包装了一个异步调用并生成一个promise实例,当异步调用返回的时候根据调用的结果分别调用实例化时传入的resolve和reject方法,then接收到对应的数据,做出相应的处理。promise不仅能够捕获错误,而且也很好地解决了回调地狱的问题,缺点是无法取消promise,错误需要通过回调函数捕获。
Generator函数是ES6提供的一种异步编程解决方案,Generator函数是一个状态机,封装了多个内部状态,可暂停函数,yield可暂停,next方法可启动,每次返回的是yield后的表达式结果。优点是异步语义清晰,缺点是手动迭代Generator函数很麻烦,实现逻辑有点绕。async/awt是基于promise实现的,async/awt使得异步代码看起来像同步代码,所以优点是,使用方法清晰明了,缺点是awt将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了awt会导致性能上的降低,代码没有依赖性的话,完全可以使用promise.all的方式。
js异步编程进化史:callback -> promise -> generator/yield -> async/awt
async/awt函数对generator函数的改进,体现在意下三点:
Vue响应式指的是:组件的data发生变化,立刻触发试图的更新
原理:Vue采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改dom。
核心API:Object.defineProperty
Object.defineProperty API的使用:
作用:用来定义对象属性
特点:默认情况下定义的数据属性不能修改。描述属性和存取属性不能同时使用,使用会报错。
响应式原理:获取属性值会触发getter方法,设置属性值会触发setter方法,在setter方法中调用修改dom的方法。
Object.defineProperty缺点:
以上5个方法中,在数据低于10000条的时候没有明显的差别,高于10000条,第一种和第二种的时间消耗最少,后面三种时间消耗依次增加,由于第一种内存空间消耗比较多,且现在很多项目不再考虑低版本浏览器的兼容性问题,所以建议使用第二种去重方法,简洁方便
undefined就是当一个变量没有被赋值或者是一个函数没有返回值又或者是某个对象不存在某个属性却去访问或者函数定义了形参但没有传递实参,这些都是undefined;null代表的是对象的值未设置,相当于一个对象没有设置指针地址就是null。undefined表示一个变量初始状态值,而null则表示一个变量被人为的设置为空对象,而不是原始状态。
让一个变量变为null,直接给该变量赋值为null就可以了。
加分:
null其实属于自己的类型Null,而不属于Object类型,typeof之所以会判定为Object类型,是因为JavaScript数据类型再底层都是以二进制的形式表示的,二进制的前三位都是0会被typeof判断为Object类型,而null的二进制位恰好都是0,因此,null被误判为Object类型。
浮动的作用:
设置浮动元素的特点:
清除浮动的方法:
.clearfix::after {
content: '';
display: table;
clear: both; //兼容IE低版本
}
.clearfix {
*zoom: 1;
}
箭头函数就是相当于匿名函数,简化了函数定义。
如果参数值只有一个可以省略()小括号,函数体只有一条语句的时候,可以省略{ }大括号和return;如果有多个参数或者函数体有多条语句是不能省略小括号、大括号、还有return的。
箭头函数的特点:
最大的特点就是没有this指向,所以它的this是从外部获取,也就是继承外部的执行上下文中的this;箭头函数也不能作为构造函数,同时通过call()和apply()方法调用一个函数的时候,只能传递参数,不能绑定this,第一个参数会被忽略;箭头函数也没有原型和super。不能使用yield关键字,所以箭头函数不能用作Generator函数。不能返回直接对象字面量。
应用场景:
作用:call、apply、bind的作用都是用来改变函数运行时的this指向。
区别:bind在改变this指向的时候,返回一个改变执行上下文的函数,不会立即执行函数,而是需要调用才会执行,但是call和apply在改变this指向的同时执行了该函数;bind只接收一个参数,就是this指向的执行上文,call和apply接收多个参数,第一个参数都是this指向的执行上文,后面的参数都是作为改变this指向的函数的参数。但是call和apply参数的格式不同,call是一个参数对应一个原函数的参数,apply第二个参数是数组,数组中每个元素代表函数接收的参数,数组有几个元素函数就接收几个元素
call的应用场景:对象的继承
bind的应用场景:在Vue或React框架中,使用bind将定义的方法中的this指向当前类
this关键字由来:在对象内部的方法中使用对象内部的属性是一个非常普遍的需求。但是JavaScript的作用域机制并不支持这一点,基于这个需求,JavaScript又搞出来另一套this机制。
this存在的场景有三种:全局执行上下文和函数执行上下文的eval执行上下文。在全局执行环境中无论是否在严格模式下,(在任何函数体外部)this都指向全局对象。在函数执行上下文中访问this,函数的调用方式决定了this的值。在全局环境中调用一个函数,函数内部的this指向的是全局对象window,通过一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向对象本身。
普通函数this指向:当函数被调用的时候,this指向全局对象window;通过一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向该对象本身;构造器调用,this指向返回的这个对象。
箭头函数this指向:箭头函数本身是没有this的,它并不会创建其自身的执行上下文,所以箭头函数的this取决于它的外部函数。
px:pixel像素的缩写,绝对长度单位,它的大小取决于屏幕的分辨率,是开发网页中常见的使用单位
em:相对长度单位,在font-size中使用时相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如width。如果当前元素的字体尺寸未设置,由于字体大小可继承的原因,可逐级向上查找,最终找不到则相对于浏览器默认字体大小
rem:相对长度单位,相对于根元素的字体大小,根元素字体大小未设置,使用浏览器默认字体大小
vw:相对长度单位,相对于可视窗口宽度的1%
vh:相对长度单位,相对于可视窗口高度的1%
rem应用:在移动端网页开发中,页面要做成响应式的,可使用rem配合媒体查询或者flexible.js实现。原理是通过媒体查询或者flexible.js,能够在屏幕尺寸发生改变时,重置html根元素的字体大小,页面中的元素都是使用rem为单位设置的尺寸,因此只要改变根元素字体大小,页面中的其他元素的尺寸就自动跟着修改
vw应用:由于vw被更多浏览器兼容之后,在做移动端响应式页面时,通常使用vw配合rem。原理是使用vw设置根元素html字体的大小,当窗口大小发生改变,vw代表的尺寸随着修改,无需加入媒体查询个flexible.js,页面中的其他元素仍使用rem为单位,就可实现响应式。
变量提升是指js的变量和函数声明会在代码编译期,提升到代码的最前面。当然这个的前提是在使用var进行声明变量的时候,并且变量提升是只对声明进行提升不对赋值提升,同时函数的声明提升会比变量的提升优先。变量提升的结果可以在变量初始化之前访问该变量,返回的是undefined。在函数声明之前可以调用该函数。
首先两者都可以用来遍历数组,但是map有返回值可以开辟一个新的空间,return出来一个length和原数组一致的数组,forEach默认是没有返回值的,返回的结果是undefined,可以通过在函数体内部使用索引修改数组元素
浏览器的事件循环:执行js代码的时候,遇见同步任务,直接推入调用栈中执行,遇到异步任务,将该任务挂起,等到异步任务有返回之后推入到任务队列中,当调用栈中的所有同步任务全部执行完毕,再将任务队列中的异步任务依次推入并执行,重复执行这一系列的行为叫作事件循环。
异步任务又分为宏任务与微任务
宏任务:任务队列中的任务称为宏任务,每一个宏任务中都包含了一个微任务队列
微任务:等宏任务中的主要功能都完成之后,渲染引擎不急着去执行下一个宏任务,而是执行当前宏任务中的微任务
宏任务包含:执行script标签内部代码、setTimeout / setInterval、ajax请求等
微任务包括Promise、Object.observe、process.nextTick等
Vue3.0是通过Proxy实现的数据双向绑定,Proxy是ES6中新增的一个特性,实现的过程是在目标对象之前设置了一层“拦截”,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
用法:ES6原生提供Proxy构造函数,用来生成Proxy实例。var proxy = new Proxy(target, hanlder)target:是用Proxy包装的被代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。handler:是一个对象,其声明了代理target的一些操作,其属性是当执行一个操作时定义代理行为的函数
Proxy的优点:可以劫持整个对象,并返回一个新对象
三栏布局,要求左右两边的盒子宽度固定,中间盒子宽度自适应,盒子的高度都是随内容撑高的,一般都是中间盒子内容多,为了保证页面渲染快,在写结构的时候,需要把中间盒子放在左右盒子的前面。实现三栏布局的方法通常是圣杯布局和双飞翼布局。
圣杯布局实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右padding,三个盒子全部浮动,设置中间盒子宽度为100%,左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
双飞翼布局实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部设置margin,三个盒子全部浮动,设置中间盒子宽度为100%,左右盒子设置固定宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
浏览器垃圾回收机制根据数据存储方式的不同可以分为栈垃圾回收和堆垃圾回收两种。
栈垃圾回收就是当一个函数执行结束之后,JavaScript引擎会通过向下移动ESP来销毁该函数保存在栈中的执行上下文,遵循先进后出原则。
堆垃圾回收:当函数执行结束,栈空间处理完成了,堆空间的数据虽然没有被引用,但是还是存储在堆空间中,需要垃圾回收器将堆空间中的垃圾数据回收。为了使垃圾回收达到更好的效果,根据对象的生命周期不一样,使用不同的垃圾回收算法。
CSRF跨站点请求伪造(Cross Site Request Forgery)和XSS攻击一样,有巨大的危害性,就是攻击者盗用了用户端额身份,以用户的身份发送恶意请求,但是对服务器来说这个请求是合理的,这样就完成了攻击者的目标。
CSRF攻击的过程原理是:
用户打开浏览器,访问目标网站A,输入用户名和密码请求登录。
用户信息在通过认证后,网站A产生一个cookie信息返回给浏览器,这个时候用户以可正常发送请求到网站A
用户在没有退出网站A之前在同一个浏览器打开了另一个新网站B
新网站B收到用户请求之后返回一些攻击代码,并发出一个请求要求访问返回cookie的网站A。
浏览器收到这些攻击性代码之后根据新网站B的请求在用户不知道的情况下以用户的权限操作了cookie并向网站A服务器发起了合法的请求。
预防CSRF攻击的策略:
XSS是跨站脚本攻击(Cross Site Scripting),不写成CSS是为了避免和层叠样式表的缩写混淆,所以将跨站脚本攻击写成XSS。攻击者可以通过向Web页面里面插入script代码,达到攻击者的目的。XSS的危害一般是泄露用户的登录信息cookie,攻击者可以通过cookie绕过登录步骤直接进入站点。XSS的分类为反射型和存储型。反射型就是临时通过url访问网站,网站服务端将恶意代码从url中取出,拼接在HTML中返回给浏览器,用户就会执行恶意代码。存储型就是将恶意代码以留言的形式保存在服务器数据库,任何访问网站的人都会受到攻击。
原型链继承:让一个构造函数的原型时另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。优点:写法方便简洁,容易理解。缺点:在父类型构造函数中定义的引用类型值的实例属性,会在子类型原型上变成原型属性被所有子类型实例所共享,同时在创建子类型的实例的时候,不能像超类型的构造函数中传递参数。
借用构造函数继承:在子类型构造函数的内部调用父类型构造函数;使用apply()或call()方法将父对象的构造函数绑定在子对象上。优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题。缺点:方法都在构造函数中定义,因此无法实现函数的复用。在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数的模式。
组合继承:将原型链和借用构造函数的组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性。优点:解决了原型链继承和借用构造函数继承造成的影响。缺点:无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
原型式继承:在一个函数A内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。本质上,函数A时对传入的对象执行了一次浅复制。ECMAScript 5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。在只有一个参数时,Object.create()与这里的函数A方法效果相同。优点:不需要单独创建构造函数。缺点:属性中包含的引用值始终会在相关对象间共享。
寄生式继承:类似于寄生构造函数和工厂模式;创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。优点:写法简单,不需要单独创建构造函数。缺点:通过寄生式继承给对象添加的函数会导致函数难以重用。
寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型。优点:高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要多余的属性,与此同时,原型链还能保持不变。缺点:代码复杂
“浏览器会立即加载js文件并执行指定的脚本,“立即指的是在渲染该script标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行”加上async属性,加载js文档和渲染文档可以同时进行(异步),当js加载完成,js代码立即执行,会阻塞HTML渲染。加上defer,加载后续文档元素的过程将和script.js的加载并行进行(异步),当HTML渲染完成,才会执行js代码。”
渲染阻塞的原因:由于js是可操作DOM的,如果再修改这些元素属性同时渲染页面,那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与js引擎为互斥的关系。当浏览器在执行js程序的时候,GUI渲染线程会被保存在一个队列中,直到js程序执行完成才会接着执行。如果js执行时间过长,这样就会造成页面的渲染不连贯。
浏览器拿到HTML,先将HTML转换成dom树,再将CSS样式转换成stylesheet,根据dom树和stylesheet创建布局树,对布局树进行分层,为每个图层生成绘制列表,再将图层分成图块,紧接着光栅化将图块转换成位图,最后合成绘制生成页面。
分层的目的:避免整个页面渲染,把页面分成多个图层,尤其是动画的时候,把动画独立出一个图层,渲染时只渲染该图层,transform、z-index等,浏览器会自动优化生成图层
光栅化目的:页面如果很长,但是可视化区域很小,避免渲染非可视区的样式造成资源浪费,所以将每个图层又划分成多个小个子,当前值渲染可视区附近区域。
computed:是计算属性,依赖其它属性值,并且computed的值有缓存,只有依赖的属性值发生改变,下一次获取computed的值时才会重新计算computed的值。必须返回结果、必须调用、不能异步监听。
watch:更多的是观察作用,支持异步,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作
computed应用场景:需要进行数值计算,并且依赖于其它数据时,应该使用computed,因为可以利用computed的特性,避免每次获取值时都要重新计算
watch应用场景:需要在数据变化时执行异步或开销较大的操作时,使用watch选项允许我们执行异步操作(访问一个API),限制我们执行该操作的频率。
Vue在更新DOM时是异步执行的,在修改数据后,视图不会立即更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取DOM,获取的仍然是未修改的DOM。
$nextTick的作用:可以让我们在下次dom更新循环结束之后执行延迟回调,用于获得更新后的dom。
$nextTick的原理:$nextTick本质是返回一个Promise
应用场景:在钩子函数created()里面想要获取操作DOM,把操作DOM的方法放在$nextTick中。
new关键字会进行如下操作:
new关键字后面的构造函数不能时箭头函数。
能。token一般是用来判断用户是否登录的,它内部包含的信息有:UID(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token的前几位以哈希算法压缩成的一定长度的十六进制字符串)
token可以存放在在cookie中,token是否过期,应该由后端来判断,不由前端判断,所以token存储在cookie中只要不设置cookie的过期时间就可以了,如果token失败,就让后端在接口中返回固定状态表示token失败,需要重新登录,再重新登录的时候,重新设置cookie中的token就行。
token认证流程:
输入地址,浏览器查找域名的IP地址,浏览器向该ip地址的web服务器发送了一个HTTP请求,在请求发送之前浏览器和服务器建立TCP的三次握手,判断是否是HTTP缓存,如果是强制缓存且在有效期内,不再向服务器发送请求,如果是HTTP协商缓存向后端发送请求且和后端服务器对比,在有效期内,服务器返回304,直接从浏览器获取数据,如果不在有效期内服务器返回200,返回新数据。请求发送出去服务器返回重定向,浏览器再按照重定向的的地址重新发送请求。如果请求的参数有问题,服务器端返回304,如果服务器端挂了返回500.如果有数据一切正常,当浏览器拿到服务器的数据之后,开始渲染页面同时获取HTML页面中的图片、音频、视频、CSS、js,在这期间获取到js文件之后,会直接执行js代码,阻塞浏览器渲染,因为渲染引擎的js引擎互斥,不能同时工作,所以通常把script标签放在body标签的底部。渲染过程就是先将HTML转换成dom树,在将CSS样式转换成stylesheet,根据dom树和stylesheet创建布局树,对布局树进行分层,为每个图层生成绘制列表,再将图层分成图块,紧接着光栅化将图块转换成位图,最后合成绘制生成页面。
Vue组件通信的方式分为两大类:一类是父子组件通信,一类是任何关系类型组件通信(父子、兄弟、非兄弟)。
父子组件通信方式:父给子传递数据,通过给子组件添加自定义属性,比如:list是父组件给子组件传递的数据,子获取父的数据,在子组件中使用props属性获取子给父传递数据,通过给子组件传递父组件的方法,子组件调用父组件的方法传递数据,比如:deleteHandler就是父组件的函数,在子组件中通过this.$emit('方法名', 参数),调用父组件的方法,并把数据传递到父组件。props是只读,不可以被修改,所有被修改都会失效和被警告。
任何关系类型组件通信方式:EventBus:使用方法是创建一个新的Vue实例,需要通信的组件都引入该Vue实例,传递数据的组件使用event.$emit('方法名', 参数)发送数据,接收数据的组件使用event.$on('名称',方法)接收数据。
entBus优缺点:
缺点:vue是单页应用,如果你在某一个页面刷新了之后,与之相关的EventBus会被移除,这样就导致业务走不下去,同时如果页面中有反复操作的业务,EventBus在监听的时候就会触发很多次,需要好好处理EventBus在项目中的关系。在vue页面销毁时,同时移除EventBus事件监听。
优点:解决了多层组件之间繁琐的事件传播,使用原理十分简单,代码量少。适合业简单,组件传递数据较少的项目,大型项目业务复杂的还是尽量使用vuex。
作用:都是控制元素显示和隐藏的指令。
区别:v-show:控制的元素无论是true还是false,都被渲染出来了,通过display:none控制元素隐藏,v-if:控制的元素是true进行渲染,如果是false不渲染,在dom树结构中不显示。
应用:v-show:适合使用在切换频繁显示/隐藏的元素上。v-if:适合使用在切换不频繁,且元素内容很多,渲染一次性能消耗很大的元素上。
盒子模型分为两种:标准盒模型和怪异盒模型。标准盒模型是由宽高内外边距边框还有盒子的内容来决定盒子大小的;怪异盒模型,所设置的宽度和高度就是盒子的大小,不会因为加了内外边距而撑开盒子。设置标准盒模型:box-sizing:content-box,设置怪异盒模型:box-sizing:border-box
原型:就是在js中每定义一个对象,对象里面都会包含一些预设的属性,所有的函数对象都有一个prototype属性,这个属性指向一个对象,该对象称为函数的原型对象。原型对象默认有一个constructor属性,值为对应的构造函数。
原型链:通过对象_proto_属性指向函数的原型对象,一层一层往上找,直到找到Object的原型对象(Object.prototype)为止,这个层层继承的链接结构叫作原型链。
HTML语义化就是指在使用HTML标签构建页面的时候,为了避免大篇幅的使用无语义化的标签,比如
、
好处作用:易于用户阅读,样式文件未加载时,页面结构清晰;有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重;方便屏幕阅读器解析;有利于开发和维护,代码更具有可读性。
浅拷贝:
是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性值是基本类型,拷贝的就是基本类型的值,如果属性值是引用类型,拷贝的就是内存地址。
深拷贝:
是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象。
区别:
浅拷贝基本类型之间互不影响,引用类型其中一个对象改变了地址,就会影响另一个对象;深拷贝改变新对象不会影响原对象,他们之间是互不影响的。
用于表单数据的双向绑定,其实就是一个语法糖,这个背后就做了两个操作:v-bind绑定了一个value属性;v-on指令给当前元素绑定input事件。
伪数组的类型不是Array而是Object,而数组的类型是Array。可以使用length属性查看长度,也可以使用 [index] 获取某个元素,但是不能使用数组的其他方法,也不能改变长度,遍历使用for in方法。
伪数组的常见场景:函数的参数arguments,原生js获取DOM:document.querySelector('div')等
伪数组转换成真数组的方法:Array.from(伪数组)
前端性能优化手段分为两类:一类是文件加载更快,另一类是文件渲染更快。加载更快的方法:让传输的数据包更小(压缩文件/图片):图片压缩和文件压缩 减少网络请求的次数:雪碧图/精灵图、节流防抖 减少渲染的次数:缓存(HTTP缓存、本地缓存、Vue的keep-alive缓存等)渲染更快的方法:提前渲染:ssr服务器端渲染 避免渲染阻塞:CSS放在HTML的head中 JS放在HTML的body底部 避免无用渲染:懒加载 减少渲染次数:对dom查询进行缓存、将dom操作合并、使用减少重排的标签
雪碧图应用场景:一般是项目中不常更换的一些固定图标组合在一起
展开语法,可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造字面量对象时,将对象表达式按key-value的方式展开。
常见场景:等价于apply的方式、将数组展开为构造函数长度的参数、字面量数组或字符串连接不需要使用concat等方法了、构造字面量对象时,进行浅克隆或者属性拷贝。
$route是路由信息对象,包括path、hash、query、name等路由信息参数;$router是路由的实例对象,包括了路由的跳转方法,钩子函数等。
利用vue-router的beforeEach事件,可以在跳转页面前进行判断用户的权限(利用cookie或token),是否能够进入此页面,如果不能则提示错误或重定向到其他页面。
重排:浏览器下载完页面中的所有组件(html、js、css、图片)之后会解析生成两个内部数据结构(dom树和渲染树),dom树表示页面结构,渲染树表示dom节点如何显示。重排是dom元素的几何属性变化,dom树的结构变化,渲染树需要重新计算。
重绘:重绘是一个元素外观的改变所触发的浏览器的行为,例如:改变visibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。由于浏览器的流布局,对渲染树的计算通常只需要遍历一次就可以完成。但table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要花多两倍的时间。
重绘重排的关系:重绘不会引起重排,但重排一定会引起重绘。
触发重排情况:页面渲染初始化时,浏览器框口改变尺寸时,元素改变尺寸时,元素改变位置时,元素内容改变时,添加或删除可见dom元素时
提供一个在页面上已存在的dom元素作为vue实例的挂载目标,可以是css选择器,也可以是一个html element实例
解析模板成render函数,执行之后返回虚拟dom
渲染显示页面并且监听data属性变化,触发页面更新
69.面向对象和面向过程
v-for遍历数组,当数组内容使用的是arr[0].xx == xx更改数据,vue无法监听到vm.arr.length = newLength也是无法检测到的
v-text:解析输出属性值,相当于innerText
v-html:解析标签型数据,相当于innerHTML
v-if、v-show:判断是否隐藏
v-for:数据循环
v-bind:绑定属性
v-on:绑定函数
v-model:实现数据双向绑定
v-once:只做一次数据渲染
v-if、v-else、v-else-if:多路分支判断
创建阶段:
beforeCreate:实例已经初始化,但不能获取DOM节点(没有data、没有el)
created:实例已经创建,仍然不能获取dom节点(有data、没有el)
挂载阶段:
beforeMount:模板编译完成,但还没有挂载到页面上,(有data,有el)
mounted:编译好的模板已经挂载到页面中(数据和dom都已经渲染出来)
更新阶段:
beforeUpdate:数据发生变化立即调用,此时data中数据是最新的,但页面上数据仍然没有更新
updated:更新结束后执行,此时data中的值和页面上的值都是最新的
销毁阶段:
beforeDestroy:当要销毁vue实例时,在销毁之前执行,实例上的事件、指令都可以使用,组件没有真正销毁
destroyed:数据、指令等完全销毁。
beforeCreate、created、beforeMount、mounted
避免组件中的数据互相影响,同一个组件被复用多次会创建多个实例,如果data是一个对象的话,这些实例用的就是同一个构造函数,为了保证组件的数据独立,要求每一个组件都必须是通过data函数返回一个对象作为组件的状态。
ES6之前创建变量用的都是var,之后创建变量用的都是let/const。
var定义的变量没有块的概念,可以跨块访问,不能跨函数访问;let定义的变量只能在块作用域里访问,不能跨块访问,也不能跨函数访问;const用来定义常量,使用时必须初始化,只能在块作用域里面访问,且不能修改。
var可以先使用后声明,因为存在变量提升;let必须先声明后使用。
var允许在相同作用域内重复声明同一个变量,而let与const不允许。
在全局上下文中,基于let声明大的全局变量和全局对象GO(window)没有任何关系。
let、const、function会把当前所在大括号(除函数之外)作为一个全新的块级上下文,应用这个机制在开发项目的时候,遇到循环事件绑定等类似需求,无需自己再构建闭包来存储,只要基于let的块作用特征即可解决。
params和query两种
第一种params的类型,通过/router/:参数名,传参,用$route.params.参数名来获取
第二种query的类型,通过/router?参数名 = 123,传参,用$route.query.参数名来获取
指的是在网页中延迟加载图片数据,是一种比较好的网页性能优化的方式。因为在比较长的网页里面有的图片会很多,所有图片都加载出来,但是用户只能看到可视窗口的那一部分图片数据,是一种浪费性能的表现。如果使用懒加载就可以很好的解决这也的问题。在滚动屏幕之前,可视区域之外的图片不会进行加载,在滚动屏幕时才加载,这样使得网页加载速度更快,减少服务器压力。
实现原理:
(1)给图片都添加上data-的自定义属性
(2)通过js代码来判断图片是否进入可视区域,如果进入就将图片src换成真实路径(window.innerHeight:浏览器可视区的高度;document.body.scrollTop || document.documentElement.scrollTop 浏览器滚动过的距离;imgs.offsetTop是元素顶部距离文档顶部的高度;图片加载条件:img.offsetTop < window.innerHeight + document.body.scrollTop)
作用:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。简单来说就是我们在methods中给数据添加了一个属性,我们能从控制台中打印出来,但是视图并没有及时更新,所以无法显示,但是借助于this.$set()方法我们就能成功解决这个问题