目录
es6新特性
闭包及其应用场景
防抖节流
HTTP强缓存和协商缓存
Promise的三种状态
Vue-router的两种模式
宏任务和微任务
Js的缺点
数据类型
异步、事件循环
原型
继承
xss和csrf是什么,如何防御
讲讲vue框架
讲讲css
数组和字符串有哪些方法
Let和var
对http有哪些了解?
Js分片具体怎么做
懒加载的原理
哪些方法能脱离文档流
垂直居中有哪些方法
Js中堆和栈的储存方式
箭头函数和普通函数区别
v-model原理
vue响应式原理
vue组件通信
diff算法
webpack打包配置
浏览器输入url到网页呈现的过程
前端的优化方法
es6新特性
- let、const、块级作用域;解构赋值
- 一些原生对象新增了方法,比如string的模板字符串;函数的默认值、箭头函数;数组的扩展运算符;对象名可以简写(key,value相同时可以只写一个)、Object.is()、Object.assign()、遍历对象:for-in、Object.keys()、Object.getOwnerPrototypeNames();Symbol类型,创建要调用函数
- 新增了Set和Map两种数据结构,set不可重复,map键值可以是任何类型
- Proxy和Reflect
- Promise、Generator和Async(Generator的语法糖,自带执行器,返回是promise)
- 支持class(实例的原型,static的方法不会被继承,必须new调用)
- module(export,import,编译时确定)
闭包及其应用场景
一个函数如果访问了外层作用域的变量,就是闭包
作用:避免命名冲突、解决循环绑定引发的索引问题、使函数内部变量不被销毁
应用场景:
- 单例模式,变量封装在闭包内部,只向全局暴露一个访问接口
- 节点循环绑定click事件,比如点击哪个按钮就输出哪个
- 函数柯里化,避免频繁调用具有相同参数函数
- 防抖节流
缺点:会出现内存泄漏的问题
防抖节流
对于高频触发的时间,用防抖节流来减少调用频率
- 防抖:n秒后再执行该事件,如果n秒内重复触发,则重新计时
搜索框输入、窗口大小调整等
- 节流:n秒内只运行一次,n秒内重复触发,只有一次生效
滚动加载、搜索联想
HTTP强缓存和协商缓存
- 强制缓存
强制缓存在未失效的时候会直接用浏览器的缓存,不会向服务器发送请求
强制缓存生效时状态码为200
相关请求头:cache-control / Expires / Pragma
- 协商缓存
当第一次请求时服务器返回的响应头没有cache-control / Expires或过期或属性设置为no-cache,浏览器第二次请求时就会与服务器协商,如果没有修改返回304,告诉浏览器可以使用缓存,如果数据有更新则返回200,将更新数据一起返回
相关请求响应头:ETag/If-Not-Match 、Last-Modified/If-Modified-Since
Promise的三种状态
Pending 进行中
Fulfilled 已成功
Rejected 已失败
.then第一个参数是resolve状态的回调函数,第二个是rejected
.catch方法是 .then(null, rejection)的别名,一般用来代替then方法的第二个参数
.finally方法用于不管promise最后状态如何都会执行的操作
all() 多个promise包装成一个新的,都fulfilled才完成,有一个rejected就rejected,但如果promise自己有catch就不会进入all方法的catch
race() 只要有一个promise状态改变就改变
Vue-router的两种模式
Hash和history
- Hash路由:
工作原理是hashChange事件,url后添加#xxx触发这个事件。#后的hash变化不会导致浏览器向服务器发出请求,即不会刷新页面,触发hashChange事件,通过监听hash值来实现更新页面部分内容
Vue-router默认的是hash模式。
会创建HashHistory对象,访问不同路由时使用HashHistory.push()或HashHistory.replace()
- History路由:
用H5的pushState()和replaceState()两个api结合window.popstate事件
- 区别:
pushState设置的url可以试当前url同源的任意url,而hash只能修改#后的部分
pushState设置的url和当前一模一样也会记录到栈中,hash设置的必须不一样才会记录
pushState通过stateObject可以添加任意类型的数据到记录中,hash只可是短字符串
hash兼容IE8以上,history兼容IE10以上
history模式需要后端配合将所有访问都指向index.html,否则会导致404
宏任务和微任务
宏任务 Macrotask是指Event Loop在每个阶段执行的任务
script、setTimeout、setInterval、setImmediate、I/O、UI rendering
微任务 Microtask是指Event Loop在每个阶段间执行的任务
promise.then、process.nextTick、Object.observe、MutationObserve
Js的缺点
- 没有命名空间,不好模块化
- 全局变量在所有模块中都可见,函数内部也能定义全局变量
- 隐式转换:+可以表示相加或者字符连接,==在两个值类型不同的时候会自动转换
- NaN表示超出了解释器的极限的数字,有很多奇怪的特性,比如NaN===NaN false
- 行尾自动分号插入
数据类型
Number、String、Boolen、Symbol、Null、Undefined、Object
异步、事件循环
Event Loop:主线程会不断从任务队列中按顺序取任务执行,每执行完一个任务都会检查微任务队列是否为空,如果不为空会一次性执行完所有微任务,再进入下一个循环去任务队列中取下一个任务执行。
Async/await:执行到await时若返回的是promise对象会阻塞当前async代码块下面的代码,先执行await中的同步代码,然后执行当前async外的同步代码,等同步代码都执行完后再回到async中,等promise状态达到fulfilled再执行之后的代码。若await返回的不是promise对象,同步代码执行完会回到当前async中执行。
原型
- JS的每个对象拥有一个原型,当访问一个对象的属性时,不仅会在对象上搜索还会搜索其原型、原型的原型,层层向上搜索。
- 对象的原型有个属性constructor,指向对象本身
- 原型分为显式原型和隐式原型,每个对象都有一个隐式原型,指向其构造函数的显式原型,多个_proto_组成的集合称为原型链
- 所有的prototype都是对象,所以他们的_proto_指向Object()的prototype
- 所有的构造函数的隐式原型都是Funciton的prototype(包括Object._proto_)
- Object.prototype的隐式原型是null
继承
子类具有父类的各种属性和方法,不需要再次编写
实现方式:
- 原型继承:父类实例作为子类的原型,let child = Object.create(father)
不能传参;
Object.create是浅拷贝,多个实例的引用类型指向同一地址,会被篡改
- 组合继承:子类中用Father.call(this),并且child.prototype = new Father()、child.prototype.constructor = Son,手动挂上构造器,指向自己
可传参,不共享父类引用属;
调用了两次父类构造函数
- 寄生组合继承:将组合继承的child.prototype = new Father()改成child.prototype = Object.create(Father.prototype)
- ES6的extend就是寄生组合继承的方式,可以不写constructor,如果写的话第一句要写super,super(200) Father.call(this,200)
xss和csrf是什么,如何防御
- csrf:跨站请求伪造
登录了信任网站的情况下,浏览器自动保存了cookie,进入攻击网站,并在攻击网站的诱导下触发对信任网站的请求。由于cookie还在有效期内,请求会被处理
措施:
- 使用cookie的sameSite属性的strict,仅允许当前网址与请求的url完全一致时携带cookie(Lax允许部分,get允许,post不允许;None都允许)
- 涉及到数据修改的操作严格使用post而非get
- HTTP协议中用Refer属性,验证refer是否为自己的域名,来确定请求来源
- 请求地址添加token,或自定义属性验证
- 显示验证方式,如密码输入,验证码输入等
- xss:跨站脚本攻击
通过页面设计时候的缺陷,利用浏览器对某处代码的解析,让浏览器执行恶意代码。如,HTML中内嵌的文本、内联JS、标签的href、src属性、onload/onerror/onclick等事件中注入突破原本限制的代码
持久型xss:将脚本植入服务器数据库里,导致每个访问的用户都会执行
非持久型:恶意代码存在url里
措施:
(大部分浏览器都自带xss筛选器,vue等框架也对xss有一些防护)
- 对用户输入内容和服务端返回内容进行过滤和转译
- 使用cookie的httponly属性,防止用过document.cookie获取cookie
- 重要内容加密传输
- 对于URL携带的参数谨慎使用
- 使用CSP,Content-security-policy请求头,在meta中配置:限制加载其他域的文件、禁止向第三方域提交数据、禁止执行未授权脚本等
讲讲vue框架
Vue是一个用于创建用户界面的js框架,它的核心特性是:
- MVVM数据驱动
Model模型层:负责处理业务逻辑和服务器进行交互
View视图层:负责将数据模型转化为UI展示出来
ViewModel视图模型层:用来连接M和V,与View之间双向绑定,帮助我们完全避免了对DOM的操作(只操作数据,界面的变动是根据数据双向绑定出来的)
MVC模式:模型 / 视图 / 控制
- 组件化
Vue允许通过组件来拼装一个页面,每个组件都是一个可复用的Vue实例,组件里可以包含自己的数据,视图和代码逻辑,方便复用
- 指令系统
带有v-前缀的特殊属性,当表达式的值改变时,响应式地作用于DOM
自定义指令:Vue.directive(),第一个参数是指令名,不带v-;组件options选项中设置directive属性,directive:{ focus:{} }。然后再模板中使用v-focus
讲讲css
- 盒模型
content、border(粗细,样式,颜色)、padding(受盒子background影响)、margin
标准盒模型:width/height + padding + border + margin
怪异盒模型:width/height + margin,width/height包含了padding和border
- 选择器
ID(#box)、class(.one)、标签 (p)、通用、属性([attribute] 所有带有attribute属性的元素)、伪类(:hover)、伪元素(::first-line)、子选择器(.one>one_1),相邻选择器(.one+.two 紧接在.one后的所有.two)
!import > 内联 > ID > 类、伪类 > 标签、伪元素 > 子选择器、相邻选择器
数组和字符串有哪些方法
- 数组
遍历:reduce、map、filter、every、some、forEach
改变:push、pop、shift、unshift、splice、sort、reserve
不变:join、slice、concat
- 字符串
concat
返回子串:slice、substr、substring
删除空格:trim、trimLeft、trimRight
repeat复制、toLowerCase转小写、toUpperCase转大写
chatAt、indexOf、includes
split转数组
Let和var
- var
有变量提升,未赋值时是undefined
可重复声明
作用域是方法作用域,在非函数作用域中定义就是全局变量
- let
声明的变量只在局部起作用
声明前使用会报错
不可重复声明
- const
有let的所有特性
声明时必须初始化,之后不可更改(实际是地址不可更改)
对http有哪些了解?
- get、post
get方法请求一个指定资源,应只被用于获取数据;post方法用于将实体提交到指定资源,通常会导致服务器上的状态变化
get回退无害,post会再次提交请求
get请求参数会被完整保留在浏览器历史记录里,post不会
get在url中传送的参数是有长度限制的,post没有
get不安全,因为参数直接暴露在url上,所以不能用来传递敏感信息
get参数通过url传递,post放在request body中
- 响应码
1消息,2成功,3重定向,4请求错误,5服务器错误
200返回数据;201服务器创建了新资源
301永久移动;302临时移动;
401未授权;403拒绝请求;404找不到请求;405方法错误
502网关错误,上游出问题;503服务不可用;504超时
- 常见header
Accept 能够接受的回应内容类型
Authorization 认证信息
Cache-control 指定缓存机制
Connection 浏览器想要优先使用的连接类型
Cookie 服务器发送的一个超文本传输协议cookie
Content-Type 请求体的多媒体类型
Content-Type: application/x-www-form-urlencoded
Date 发送该消息的日期
Expect 客户端要求服务器做出的特定行为
Host 服务器的域名和端口号
User-Agent 浏览器的身份标识
Js分片具体怎么做
读取文件的内容,用MD5实现文件的唯一性,然后对文件进行分割(用Blob的slice方法,包含md5值,文件大小,共多少块,第多少块),上传
后端可以根据前端传的md5值,到服务器查找之前文件的合并信息,返回数据告诉前端从第几节上传,实现断点续传
懒加载的原理
访问页面时,先把图片的路径替换成一张占位图的路径,当图片进入可视区域才把图片路径替换成真实路径
监听页面滚动,当元素到浏览器窗口的距离(offsetTop)小于document到浏览器窗口的距离(scrollTop)+可视区域的高度(document.body. clientHeight),img.src改成真实路径
哪些方法能脱离文档流
- float 使用时其他盒子会无视该元素,但盒子内的文本依然会为这个元素让出位置,环绕
- absolute 绝对定位,相对该元素的父类(不满足就继续向上查询)元素进行定位
- fixed 完全脱离文档流,相对于浏览器窗口进行定位
垂直居中有哪些方法
- position: absolute
1) top/left/right/bottom都设置为0,margin: auto
2) top: 50%,margin:负自身的50%,如margin:-50px
3) top:50%,transform:translate(-50%,-50%)
- 父类元素display: flex,align-items:center(justify-content:center 水平居中)
Js中堆和栈的储存方式
基本类型存储在栈中,引用类型额对象存储在堆中,引用地址放在栈中
箭头函数和普通函数区别
- 箭头函数的this指向它定义时所在对象,而非调用它的对象
- 不会进行变量提升
- 不可以作为构造函数,不能使用new
- 没有arguments对象,如果要用可以用rest
- 不可以使用yield命令,所以不能用作Generator函数
v-model原理
实际是v-bind和input事件
:value=”value” @input=”value = $event.target.value”
vue响应式原理
- vue2是采用发布-订阅者的模式,通过Object.defineProperty()来劫持各个属性的setter、getter。Vue实例创建时,会遍历所有DOM对象,为每个数据属性添加get和set,但添加或删除属性并不会触发;数组是通过重写数组的Array.prototype对应的方法(push/pop/shift/unshift/sort/reverse/splice),触发方法时视图更新
- Vue3是通过ES6的Proxy,在目标对象外设置一层拦截,外界的操作都会通过这层拦截,可以拦截到对象属性的读取、设置、新增删除等,还可以直接监听数组的变化
vue组件通信
- props
父传子,子组件设置props属性,接受父组件传来的参数
- $emit
子传父,通过$emit触发自定义事件,第二个参数为传递的数值,父组件绑定监听器获取组组件传来的参数
- ref
父组件在使用子组件的时候设置ref属性ref=” xxx”,this.$refs.xxx获取子组件实例
- EventBus
兄弟组件传值,创建一个中央时间总线EventBus,兄弟组件通过$emit触发自定义事件,另一个兄弟组件通过$on监听自定义事件
- $parent或$root
兄弟组件传值,通过共同祖辈或root,一个this.$parent.emit(‘add’),另一个this.$parent.on(‘add’, this.add)
- Attrs和listeners
- Provide和Inject
- Vuex
是状态管理工具,集中式存储管理应用的所有组件的状态
State:用来存放共享变量
Getters:相当于计算属性,返回的值会根据它的依赖被缓存起来,只有依赖值发生变化才会被重新计算
Mutations:用来存放修改state中数据的方法,store.commit方法更改数据
Action:通常用来做异步操作,需要在mutation的基础上进行
Module:分割的模块,每个模块拥有自己的state、getters、mutation、actions
diff算法
通过同层的树节点进行比较的算法,只比较同层,循环从两边向中间比较
Vue中用于虚拟DOM渲染成真实DOM的新旧节点比较,
先同级比较,相同则直接复用。
然后比较子节点,如果旧的有子节点,新的没有,会把旧的删除;如果旧的没有新的有,会把新增的子节点插入旧的。
都有子节点时,先比较第一个是否一样,一样的话移动新旧的start指针,不一样则会从最后一个开始比较;如果头尾都不相等则比较新头和旧尾,一样就把旧尾移到前面去,然后end指针往前一位,start指针往后一位。如果存在key则会直接用key去旧的子节点中找,找到就移动到最前面,start往后一位,没有就直接插入。
最后把旧的多余节点删掉。
webpack打包配置
webpack是用于JS应用程序静态模块的打包工具
- 初始化:从配置文件和shell中读取并合并参数,初始化需要使用的插件和配置插件
- 编译构建:从Entry出发,对每个Module串行调用对应的Loader进行翻译,再找到该Module依赖的module,递归进行编译
- 输出:对编译后的Module组合成chunk,转换成文件输出
常用配置:
entry:入口文件,从哪个开始打包
output:输出,打包好的文件输出到哪里
module:配置loader,webpack本身只能打包js/json,打包css、img、html等需要各种loader,通过npm下载即可
plugins:插件
mode:打包模式,development和production
浏览器输入url到网页呈现的过程
- url解析:协议、域名(确定服务器)、端口(确定服务器中的具体应用)、路径(访问的资源位置)、查询字符串(详细描述)
- DNS查询:获取到域名对应的服务器的IP地址
- TCP连接:发送syn,收到发送SYM/ACK的数据包,收到发送标有ACK的数据包
- 发送http请求:建立tcp连接后发送请求
- 响应请求:浏览器收到服务器响应的资源,进行解析,开始页面渲染
- 页面渲染:
- 解析HTML,构建DOM树
- 解析CSS,构建CSS规则树
- 合并DOM树和CSS规则,生成Render树
- 布局render树,针对浏览器的各种状态,计算各元素的尺寸、位置
- 绘制render树,绘制页面像素信息
- 浏览器将各层信息发送给GPU,GPU会将各层合成,显示
前端的优化方法
- 加载
减少http请求数,合并css和js,使用css精灵图
缓存资源
压缩代码,多余的缩进和换行
样式放在头部使用link引入,脚本放在尾部使用异步加载
懒加载、滚屏加载等按需加载方法
进入页面时先使用loading,加载完成后再显示页面
压缩图像,使用css代替图像
静态资源不适用cookie
- 执行
避免img、iframe的src为空,空的话会重新加载
避免重置图像大小,会引发重绘
- 渲染
减少DOM节点
动画尽量使用css3动画,5个元素以上的话使用canvas
使用requestAnimationFrame代替setTimeout
对滚动、鼠标移动这类高频时间使用防抖节流
- 样式
尽量不在html中写style
避免css表达式
不滥用float,float渲染时计算量比较大
不声明太多的font-size,会影响css树的效率
值为0时不写单位
- 脚本
尽量改变class而不是style
尽量使用id选择器