前端宝典(自用)

184 阅读6分钟

一、HTML篇

1.h5新增了哪些东西

  canvas

  audiovideo

  localStroge、sessionStorage

  语义化标签:articleheaderfooter

2.doctype的作用

  位于html文件的第一行,告诉浏览器的解析器需要用什么文档标准来解析这个文档
  

3.重绘与回流(重排)

渲染树的节点发生了结构性变化,比如高度、宽度的更改,则会造成回流(重排)
渲染树的节点发生了非结构性变化,比如背景色的变化,则会造成重绘
回流一定会重绘,但是重绘不一定回流

二、css篇

1.css的盒子模型

border-box:ie怪异盒模型(内容包含paddingmargincontentcontent-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.垂直居中的方式

   父相子绝,子divtopleft分别是50%,并且margin-topmargin-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的新特性

   增加了constlet
   增加了模板字符串(`${}`)
   增加了箭头函数
   引入了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 
symbolnull也会被认为是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. routeroute和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拿到每个属性的gettersetter,
在数据变动时发布消息给监听者,触发相应的监听逻辑

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中)