一、HTML篇
1.h5新增了哪些东西
canvas
audio、video
localStroge、sessionStorage
语义化标签:article、header、footer
2.doctype的作用
位于html文件的第一行,告诉浏览器的解析器需要用什么文档标准来解析这个文档
3.重绘与回流(重排)
渲染树的节点发生了结构性变化,比如高度、宽度的更改,则会造成回流(重排)
渲染树的节点发生了非结构性变化,比如背景色的变化,则会造成重绘
回流一定会重绘,但是重绘不一定回流
二、css篇
1.css的盒子模型
border-box:ie怪异盒模型(内容包含padding、margin、content)
content-box:W3C标准盒模型(内容只包含content)
2.css中link和@import的区别
link属于html标签,没有兼容问题,页面在被加载时会同时加载link,权重高于@import
@import属于css提供的,只有在ie5以上才能识别,页面加载完毕后才会加载
3.css优先级
!important > 内联 > id > 类 > 标签
4.伪类和伪元素
伪类通常是给元素添加一些动态特性,比如hover active visit
伪元素通常是创建一些不在文档树中的内容,比如before、after
5.css单位
px:绝对单位,精确像素
em:相对单位,相对于父节点的font-size
rem:相对单位,root em,相对于html节点的font-size
vw:viewport width,视窗宽度
vh:viewport height,视窗高度
%:相对于父节点的宽高比
6.垂直居中的方式
父相子绝,子div的top和left分别是50%,并且margin-top和margin-left分别是他宽度的一半的负值
使用flex布局,通过justify-content或者align-items设置为center
行高=高
7.css布局方式
table布局
flex布局
响应式布局
float布局
8.padding和margin的区别?
作用对象不同,padding作用于自身,margin作用于外部对象
9.如何让谷歌浏览器支持小字体
通过scale来实现,transform:scale(0.5)
三、js篇
1.async和await
这两者属于组合使用,是用来让异步代码看上去像是同步代码在顺序执行,await用来等待一个异步方法的执行完成
2.数组的方法
改变原数组:
pop(从末尾删除一个元素,返回被删除元素)
push(从末尾添加一个或多个元素,返回新的长度)
shift(从开头删除一个元素,返回被删除元素)
unshift(从开头添加一个或多个元素,返回新的长度)
reverse(数组反转)
sort(将数组按一定逻辑排序)
splice(用于插入、删除或者替换元素)
不改变原数组:
concat(连接两个或多个数组)
every(检测数组的每个元素是否都满足条件)
some(检测数组中是否有元素满足条件)
filter(将数组中满足条件的元素过滤出来返回一个新的数组)
indexOf(搜索数组中的元素,返回他的索引)
join(将数组中元素按照一个标识组合拼成字符串)
toString(将数组转换成字符串)
lastIndexOf(返回数组中某元素最后一次出现的索引)
map(通过处理指定的数组,并返回新数组)
slice(选取数组中的一部分返回新的数组)
forEach(遍历数组)
3.原型链
每一个实例对象上都有个proto属性,他指向的是构造函数的原型对象,
构造函数的原型对象本身也是对象,所以就有proto属性,它又指
向了上一个原型对象,直到找到Object,这样一个一个向上找的过程就形成了原型链
4.闭包
简单地说,就是在函数中返回函数,内部函数可以访问外部的变量,
这个变量叫做自由变量
为了保存变量,使其常驻内存,解决变量的私有化问题
5.es6的新特性
增加了const和let
增加了模板字符串(`${}`)
增加了箭头函数
引入了module的概念
6.js的数据类型有哪些
基础数据类型:
string(字符串)
number(数字)
null(不存在)
boolean(布尔)
undefined(未定义)
symbol(独一无二,常用来解决键名重复问题)
bigint(安全的大数字)
引用数据类型:
object(包含了function、array、date等)
基础类型在复制后是2个独立的东西,而引用类型则是
复制了一个指针,改变一个值也会影响另一个值
7.同源策略
是指协议名、域名、端口名都一致的情况下就是同源,
违背了同源策略,就会产生跨域,跨域的解决方式有
jsonp(只支持get请求)
cros(服务端在后台对接口的access-origin进行设置)
通过webpack自带的devServer(开发服务器)中进行proxy的设置
8.什么是promise
promise主要用于异步计算,可以将异步操作队列化,
按照期望的顺序执行
他有3种状态 pending(等待中)、fulfilled(成功)、rejected(失败),
他的状态改变,只会从pending变为后者两个,一旦变化,状态就凝固了
9.什么是递归
递归就是指在函数内部调用自己
优点是逻辑清晰,可读性强
缺点是效率低,可能导致内存溢出
10.let和const的区别
两者都不允许重复定义对象,不存在变量提升,
const必须在定义时就赋值,let则可以只定义,他们都会形成封闭作用域
const定义的是常量,不允许修改,如果定义的是对象,则可以修改
11.存储方式
cookie:在过期时间后自动删除
localStorage:不会自动删除,存储持久数据,浏览器关闭后
也不会清除除非手动清除
sessionStorage:临时存储,关闭浏览器后自动删除
cookie不能超过4K,后两者可以达到5M或更大
cookie始终会参与到与服务器的通信中,通常放在header里面(即使不需要)
12.普通函数和箭头函数的区别
箭头函数没有自己的this,他指向上一个作用域,普通函数指向的是自己
改变this指向:
call,apply(立即执行)
bind(需要再手动调用一次)
call,bind(传递的是参数列表)
apply(传递的是数组)
13.typeof会返回哪些值
string
number
boolean
undefined
object
function
symbol(null也会被认为是object)
14.预解析
在当前作用域中,js会将var声明的变量和function声明的变量进行提前声明,同时function还会提前被定义出来
15.事件冒泡和事件委托
冒泡:当一个事件发生后,会从该节点一直向上传播,触发每一层的父节点事件,
直至找到document对象(自下而上)。阻止冒泡则可以用e.stopPropagation(),
取消任务的默认行为可以用e.preventDefault()
委托:当需要给一个节点绑定事件时,该节点数量大或者是动态添加的,
不能确切的绑定至其上,或者为了节约内存,没必要给每个子节点都绑定事件,
此时可以将事件挂载在它的父节点上面,由父节点向下传播,实现子节点的触发(自上而下)
16.script 中 defer 和 async 的区别
script:会阻碍html的解析,直到该脚本下载完毕
async script:可能不会阻碍html的解析,使用异步的方式下载该脚本,下载完毕立即执行
defer script:完全不会阻碍html的解析,解析完毕后才开始下载脚本
17.事件循环
Event Loop:js处理事件时,同步任务是立即执行的,异步任务则又被分为宏任务和微任务,
微任务享有优先执行权,并且总会将当前的微任务全部执行完成后,再执行宏任务,
再执行完一条宏任务后如果发现有微任务则又立即执行微任务,若没有微任务则继续执行下一条宏任务
18.原型
原型:
每个对象都有_proto_属性,属于隐式原型,指向该对象的原型对象
每个函数都有prototype属性,属于显示原型属性
19.防抖节流
防抖:n秒后执行一次事件,如果重复触发,则重新计时(输入框搜索、下拉滑动加载)
const debounce = (fn, wait) => {
let timeout = 0
return () => {
if (timeout) clearTimeout
timeout = setTimeout(() => {fn()}, wait)
}
}
节流:n秒内只执行一次事件,如果重复触发,则在下一个n秒后才会再次执行(只有timeout被清空后才继续执行下一次)
const throttle(fn, wait) => {
let timeout = null
return () => {
if (!timeout) {
timeout = setTimeout(() => {
fn()
timeout = null
}, wait)
}
}
}
20.作用域链
一般来说,变量取值到创建这个变量的作用域中去取,如果拿不到,
就向上层作用域查找,直到查到全局作用域,这么一个查找的过程形成了一条作用域链
21.深拷贝与浅拷贝
浅拷贝:藕断丝连,改变一个会影响另一个
深拷贝:互不影响,两个独立的空间
四、vue篇
1.vue双向绑定的原理
在vue中,采用m(数据层)v(视图层)vm(数据视图交互层)的方式,
修改数据就能直接引起dom元素的变更,使用v-model指令来完成这一步
v-model的本质其实是v-bind和v-on的语法糖,其实是绑定了一个value的属性和input的事件
2.vue的生命周期有哪些
beforeCreate(创建前,this.$el为空,this.$data为空)
created(创建后,this.$el为空,this.$data有值)
beforeMount(在组件装载之前,,this.$el为空,this.$data有值)
mounted(组件装载完成,真实dom已经生成,,this.$el有值,this.$data有值)
beforeUpdate(在组件数据更新之前)
updated(组件数据更新后)
beforeDestory(组件销毁之前,一般用来做订阅的取消或者定时任务的清理)
destoryed(组件已经销毁)
activated(keep-alive的生命周期,组件在被激活时调用)
deactivated(keep-alive的专属,组件在被销毁时调用)
3.http请求应该在哪个生命周期完成
从理论上讲,不管放在created或者mounted中请求都是可以的
因为http请求是异步任务,从js的事件轮询机制可以知道,异步任务是会慢于同步任务执行的
所以不管放在哪个周期中,都是会等这两个周期内部的同步任务执行完成后才会执行http请求
但是,如果是有依赖关系的父子组件的情况下,如果写在created中,则先是父组件的http请求先完成,
子组件的http请求后完成
如果写在mounted中,则是子组件的http请求先完成,父组件的http请求后完成
4.v-if和v-show的区别
v-if是直接将dom元素从页面上删除,再次切换需要重新渲染
v-show是通过改变display属性来控制显隐的,切换不需要进行重新渲染
一般来说,如果需要频繁的切换,建议使用v-show
5.v-for为什么需要绑定key
这是底层的diff算法需要的,给dom元素上绑定唯一的key值,可以很快的实现比较,加快页面的渲染,避免重复渲染
6.vue中的data为什么是一个函数而不是一个对象呢
因为js中对象是引用类型,组件是可以复用的,如果将data作为对象,
那么修改一个实例中的data值将会引起其他实例中的data值也发生变化
7.vue的单向数据流
数据从父组件传到子组件,子组件对这些数据没有修改的权限,只能请求父组件中的方法进行更改,
直接修改控制台会报错
8.slot
插槽的作用就好比是一段占位符,当复用组件时,使用对应的插槽名称,就可以替换掉占位内容,对复用和扩展组件有很大的好处
插槽分为匿名插槽,具名插槽和作用域插槽(可以传值)
9.keep-alive的作用
用来缓存组件,在组件的切换过程中执行的不是销毁操作而是将其保存在内存中,
他有自己的生命周期,activated(组件被激活)、deactivated(因为使用了keep-alive就不存在销毁操作了,
所以原本的销毁相关的生命周期无法使用,则使用这个进行代替)
首次进入被缓存组件,执行beforeCreate、created、beforeMount、mounted、**activated**
后面再进入则只执行activated
10.vue的diff算法(遍历循环比较)
1.vue在进行diff时,会调用patch函数,一边比对一边给真实的dom打补丁
2.vue在同级同层比较时,如果节点名称相同但是class不同,则会认为是不同类型的元素,就会删除重新创建
3.vue在比较时,会在旧集合和新集合两端同时存在指针,在比对时指针不断向中间移动
11.props
props: ['id'], 表示只是接收id这个参数
props: {
id: Number,
default: 0
}, 表示可以对id这个参数进行一些限制
12.父子之间通信方式
父使用子的方法:this.$refs.children.xxx()
子使用父的方法:this.$emit('xxx', params)
子组件使用.sync
<child :data.sync="xxx" />
$parent/$children/props/eventbus/provide,inject/$attrs,$listeners
13.vue的data必须是函数
vue之间的组件是可以复用的,如果data是对象的形式,则引用的是同一个地址,
无法将data独立出来,修改一个组件的data值其他组件里面的data也会受影响
14.methods、computed、watch
methods没有监听依赖的效果,每次访问methods将会重新计算
computed具有监听依赖的效果,每次访问computed只有依赖项发生了变化才会
重新求值,起到了一个缓存的作用。另外它可以监听多个依赖,适用于依赖多个值并进行一段计算的场景
watch则是用来监听单个依赖值的,可以拿到上一次的数据和新的数据,
适用于监听单个值变化后执行一段业务逻辑的场景
15.过滤器
常见写法:{{ message | filter(arg1, arg2) }}
变量与过滤器之间用大竖号分割开,将过滤器的方法写到filters里面,如:
filters:{
xxx:function(args) {
}
}
接收的参数中,message将作为第一个参数,arg1为第二个,以此类推
16.ref
用来创建引用对象的方式,如果用在dom元素上,引用指向的就是dom元素,
如果用在组件上,指向的就是组件实例,可以使用this.$refs来进行获取
17.nextTick 的原理和用途
数据修改后的延迟回调,立刻获得新的dom。
18.性能优化
1.减少data的数据,每个data都会被watch,尽量拆成组件
2.在循环的dom元素或组件上加入唯一的key标识,帮助快速完成diff算法
3.使用keep-alive缓存组件
4.第三方模块按需引入
5.v-for和v-if不能同时在一个节点或组件上使用
19. router的区别
总的来说,$router是用来操作路由的,它是全局的router实例,里面有很多方法
$route则是用来获取路由信息的,比如query、params等,它是当前激活的路由对象
20.动态路由匹配
形如/user/:id这样的路径,叫做动态路由匹配,类似于一些详情页面,可以通过route.params.id获取参数
21.权限路由动态添加
路由分为公共路由和权限路由,权限路由则需要在登录成功后的角色信息中进行比对,
符合权限的路由才可以添加到当前用户所呈现的页面中,通过router.addRoutes方法加入
22.路由懒加载
如果不使用懒加载的话,当我们的路由特别多的情况下,在打包环节将会导致打包的js体积异常庞大,
但其实没必要一次性完全打包进去,只需在访问那个路由的时候再进行加载即可
推荐的懒加载方式是es6的import方法:
component: () => import('/* webpackChunkName: 'xxx' */...路径')
如果多个路由指定了相同的webpackChunkName,他们将会打包成一个js,否则则一个路由打包成一个js
23.v-for和v-if为什么不建议同时使用
因为v-for的优先级是高于v-if的,如果同时存在的话,就相当于在每个遍历中去进行if判断,
一旦当被遍历的数组很庞大时,性能开销也会很大,得不偿失。可以使用computed来完成
24.vue-router hash和history
hash:在浏览器地址栏中会带有#,在#后面的值的变化,并不会引起浏览器的请求,
兼容性较好,刷新页面也会正常加载
history:借助于H5新的api:pushState和replaceState来实现改变url而不发出浏览器的请求,
地址看上去更加优雅,但是刷新页面会返回404,需要在后端将页面配置到首页
25.响应式原理
本质是采用数据劫持结合发布订阅的方式,结合Object.defineProperty拿到每个属性的getter和setter,
在数据变动时发布消息给监听者,触发相应的监听逻辑
26.eventbus
建立bus文件
import Vue from 'vue'
export default new Vue()
发送消息
import bus from './bus'
bus.$emit('share', xxxx)
接受消息
bus.$on('share', xxxx)
移除消息
bus.$off('share')
27.http请求可以在beforeCreate完成吗
如果该请求没有封装成方法写到methods中,那么是可以的,
因为在beforeCreate中是无法访问到methods中的方法的,此时的dom及数据都尚未准备好
28.父子之间生命周期的加载顺序
父优先创建,子优先挂载
父:beforeCreate created beforeMount
子:beforeCreate created beforeMount mounted
多个子的话同上
父:mounted
五、vuex篇
1.vuex的五大核心
state: 全局数据管理
getters:类似于computed,返回对state处理后的结果
actions:提交mutations,可以写异步操作
mutations:修改state的值,只能写同步操作(若写异步则无法准确追踪state的变更)
modules:模块化管理,将state中的数据进行分类
modules中若有相同的actions则均会触发,解决方案是在每个module中声明namespaced: true这个属性
然后再调用的时候使用module的文件名称+action名称(user(module名称)/setToken(action名称))
2.为什么不能在actions中修改state
在未开启严格模式下,是可以修改的,但是不提倡
但是严格模式下控制台会抛出异常并且actions是异步的,不利于调试
vuex-persistedstate也只会读取mutations中state的变化而重写存储key
严格模式开启:
new Vuex.Store({ xxx, strict: true })
3.vuex的语法糖
state:
1. this.$store.state.xx
2. mapState({xxx}) (写在computed中)
getters:
1. this.$store.getters.xx
2. mapGetters({xxx}) (写在computed中)
actions:
1. this.$store.dispatch(xx)
2. mapActions([xx]) (写在methods中)
mutations:
1. this.$store.commit(xx)
2. mapMutations([xx]) (写在methods中)