1.闭包
闭包:
定义 当一个函数的返回值是另外一个函数,而返回的函数如果调用了父函数的内部变量,且返回的那个函数在外部被执行,就产生了闭包.
闭包的三个特性
1:函数套函数
2:内部函数可以直接访问外部函数的内部变量或参数
3:变量或参数不会被垃圾回收机制回收
闭包的优点:
1:变量长期驻扎在内存中
2:避免全局变量的污染
3:私有成员的存在
闭包的缺点
常驻内存 增大内存的使用量 使用不当会造成内存的泄露.
调用方式:
//1:直接调用
a()()//内部函数的执行
//2:通过赋值在调用var f = a(); f()
2.作用域
作用域分为全局作用域和局部作用域
全局作用域:变量在函数或者代码块{ }外定义,即为全局作用域。
局部作用域:在函数内部定义的变量,就是局部作用域。局部作用域内,对外是封闭的,从外层的作用域无法直接访问函数内部的作用域
作用域链:自由变量的向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,就形成了作用域链。
3.继承
class继承:
class 相当于es5中构造函数
class中定义方法时,前后不能加function
class中只能定义方法,不能定义对象,变量等
class和方法内默认都是严格模式
ES5中继承:原形链继承+构造函数继承
原型链继承:父类的实例作为子类的原型
缺点: 引用类型值的属性会被所有实例共享。
借用构造函数继承:在子类,使用call()调用父类方法,并将父类的this修改为子类的this.就是把父类的实例属性复制了一份放到子类的函数内
优点:
1 可以传递参数
2 解决了原型中所有实例共享的问题
组合继承:既能调用父类实例属性,又能调用父类原型属性
4.原型
原形链:
每个函数都有一个prototype,叫做显示原型
每个实例都有一个_proto_,叫做隐式原型
实例的隐式原型指向构造的显示原型
prototype constructor protp三者之前区别关系?
实例化和原型对象的constructor属性指向构造函数
构造函数prototype指向原型对象
实例化对象的_proto_指向原型对象
5.promise 手写异步加载图片
promise是一个容器,里面保存异步操作的结果
promise是一个对象,可以获取异步操作的最终状态(成功/失败)
promise是一个构造函数,对外提供统一的API自身上有all,reject,resolve等方法,原型上有then,catch方法
promise两大特点
promise对象状态不受外界影响
promise的状态一旦改变,不会在变,任何时候都可以得到这个结果,状态不可逆,只能由pending变成fulfilled或者pending变成rejected
三种状态:pending初始状态 fulflled成功状态 rejected失败状态
1 |
|
6.async/await
async 是“异步”的简写, async 用于声明一个异步的 function
await 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成。
特点:
asayc的用法,它作为一个关键字放到函数前面,这样普通函数就变为了异步函数
异步async函数调用,跟普通函数的使用方式一样
异步async函数返回一个promise对象
async函数配合await关键字使用是异步方法,但是阻塞式的
7.双向数据绑定
vue的双向数据绑定只要是采用数据劫持结合开发者和订阅者方式 通过Object.defineProperty()来劫持各个属性的setter,getter, 在数据变动时发布消息给订阅者,触发相应监听回调
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者。 通过Observer来监听自己的model的数据变化,通过Compile来解析模板指令。
8.vitral Dom
virtual-dom(简称vdom)的概念得益于react的出现react这个框架的非常重要的特性之一。
在vue的整个应用生命周期当中,每次需要更新视图的时候便会使用vdom
vdom算法是基于snabbdom算法所做的修改。
实现
①用js对象构造一个虚拟的dom树,插入到文档中;
②状态变更时,记录新树和旧树的差异;
③把上面的差异构建到真正的dom中
9.vuex
Vuex 是适用于 Vue.js 应用的状态管理库,为应用中的所有组件提供集中式状态存储与操作,保证了所有状态以可预测的方式进行修改。
优点 当state中定义一个数据后,可以在所在项目的任何组件中进行获取,修改,修改可以得到全局的变更
运行机制:vue提供数据来驱动试图,通过dispath派发actions,通过commit调用mutations的方法,修改state的数据
①state:定义初始数据。
②mutations:更改Vuex的store中的状态的唯一方法是提交mutation
③getters:可以对 state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性
④actions:异步操作初始数据,其实就是调用mutations里面的方法。
⑤module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。
10.keep-alive?
<keep-alive>
标签:是Vue的内置组件,在组件切换过程中将状态保留在内存中,取消组件的销毁函数,防止重复渲染DOM
当用它包裹 <router-view>
时,会缓存不活动的组件实例,而不是销毁它们。
和 <transition>
相似,它自身不会渲染一个 DOM 元素。
使用 <keep-alive>
组件后即可使用 activated() 和 deactivated() 这两个生命周期函数
11.组建通信?
父组件传到子组件 通过props属性给子组件通信的
子组件向父组件传值 父组件通过自定义事件,接受子组件传递来的参数,子组件通过$emit触发父组件上的自定义事件发送参数
ref通信:ref可以为自己的dom做出独有的标记,利用this.$refs来获取从而操作
兄弟通信:bus事件
- 在其中一个组件的 挂载钩子函数上做事件的声明
- 在另一个组件中通过bus.$emit(“”)来触发这个自定义事件
12.自定义组件
在子组件中创建模板,在props中接受父组件传递的数据,在父组件中引入子组件,然后在components中创建子组件,挂载到父组件的template中
props 父传子使用 $emit(参1,参2)子传父时使用 参1是自定义的事件名,参2是要传递的数据,在父组件的子组件中绑定自定义事件名,调用一个函数,函数的形参就是传递的数据
13.自定义指令
自定义指令分为:全局自定义指令,局部自定义指令。
钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
inserted:被绑定元素插入父节点时调用。
bind:只调用一次,指令第一次绑定到元素时调用。
update:所在组件的 VNode 更新时调用
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
**指令钩子函数会被传入以下参数:
**
el:指令所绑定的元素,可以用来直接操作 DOM 。
binding:一个对象,包含以下属性:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression:字符串形式的指令表达式
arg:传给指令的参数
modifiers:一个包含修饰符的对象
vnode: Vue编译生成的虚拟节点
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
14.路由守卫
全局路由守卫有个两个:一个是全局前置守卫,一个是全局后置守卫
① 全局导航钩子:一般用来判断权限,以及页面丢失时需要执行的操作;
beforeEach()每次路由进入之前执行的函数。
afterEach()每次路由进入之后执行的函数。
beforeResolve()2.5新增
② 单个路由(实例钩子):某个指定路由跳转时需要执行的逻辑。
beforeEnter() beforeLeave()
③ 组件路由钩子:
beforeRouteEnter()
beforeRouteLeave()
beforeRouteUpdate()
**路由独享守卫:**路由独享守卫是在路由配置页面单独给路由配置的一个守卫
15.生命周期函数
beforeCreate(创建前):data 和 methods 的数据没有初始化
created(创建后):data和methods中的数据已经初始化完毕
beforeMount(载入前):模板编译好了,没有挂载到页面,页面此时是旧的
mounted(载入后):此时页面已经渲染完毕,这个是最早可以操作dom的钩子函数
beforeUpdate(修改前):页面显示的数据旧的,data的数据是新的
updated(修改后):页面于data的数据已经同步
beforeDestroy(销毁前):该钩子函数执行的时候,数据还可以使用
destroyed(销毁后):数据已经销毁完毕
activated(keep-alive组件激活调用)
deactivated(keep-alive组件停用调用)
errorcapture(捕获来自子孙组件错误是调用)
16.跨域(jsonp,vue)
理解跨域的概念:协议、域名、端口都相同才同域,否则都是跨域
jsonp 实现原理:主要是利用动态创建 script 标签请求后端接口地址,然后传递 callback 参数,后端接收 callback,后端经过数据处理,返回 callback 函数调用的形式,callback 中的参数就是 json
优点:浏览器兼容性好,
缺点:只支持 get 请求方式
vue跨域: 在vue.config.js的空文件中,配置文件
target:要访问的接口的基础地址
changeOrigin:是否可以跨域
secure:是否进行 https 验证
pathRewrite:将 api 替换成 ‘ ‘ 中的值
17.常见状态码
200 OK //客户端请求成功
400 //客户端请求有语法错误,不能被服务器所理解
401 //请求未经授权
403 //服务器收到请求,但是拒绝提供服务
404 //请求资源不存在,输入了错误的 URL
500 //服务器发生不可预期的错误
503 //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
18.项目流程
创建脚手架下载element -ui 配置路由 创建登入页面 在element-ui复制表单 和表单验证 把账号密码进行绑定 根据接口判断登入状态是否 !=200登入失败,==200登入成功 this.$router.push 跳转到后台首页,存入token值 登入完成进行后台首页基本布局 分为头部区域 主题区域 侧边栏 进行相对应的css布局 然后配置axios拦截器 进行token验证 在main.js中添加代码,在将axios挂载到vue原型 请求侧边栏数据 通过v-for双重循环渲染左侧菜单 根据左侧菜单的路由制作相应的用户管理,权限管理,商品管理,订单管理,数据统计根据项目文档完成里面对应的功能.
19.深拷贝 手写代码
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响, 对一个对象的修改并不会影响另一个对象。
为什么要使用深拷贝: 我们希望在改变新的数组(对象)的时候,不改变原数组(对象)
可 以 使 用 for in 、 Object.assign 、 扩 展 运 算 符 … 、Array.prototype.slice()、Array.prototype.concat() 、递归等递归函数实现深拷贝
20.输入url到页面出现发生了什么
大致过程是这样的:
\1 DNS 解析
\2. TCP 连接
\3. 发送 HTTP 请求
\4. 服务器处理请求并返回需要的数据
\5. 浏览器解析渲染页面
\6. 连接结束
这里会延伸出问 http 状态码,和三次握手和四次挥手相关问题:
三次握手
第一次握手
客户端向服务端发送连接请求报文段。请求发送后,客户端便进入 SYN-SENT 状态。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示: 服务端发来的连接同意应答已经成功收到。
CP 连接的释放一共需要四步,因此称为『四次挥手』。
TCP 连接是双向的,因此在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接。
21.虚拟DOM和diff算法
虚拟dom就是用对象的方式区代真实的dom操作。
当页面打开时浏览器解析HTML元素,构建一个dom树,将状态保存起来,在内存中模拟dom操作,又会生成一个dom树,两个进行比较,根据diff算法找出不同的地方,之渲染一次不同的地方
diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom
22.vue组件中的data为什么是一个函数
data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。
Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了
23.vue项目打包
一、修改请求静态资源的路径
打开config下的index.js文件,修改assetsPublicPath的值,从‘/’改为‘./’。即从根路径改为相对路径。
1 | build: { |
二、修改本地图片的路径
打开build下的utils.js文件,增加 publicPath:’../../‘
1 | if (options.extract) { |
三、在终端运行npm run build。
25.防抖和节流
防抖: 触发高频事件后 定时器内函数只会执行一次,如果定时器内高频事件再次被触发,则重新计算时间
场景:
按钮提交场景:防止多次提交按钮,只执行最后提交的一次。
节流 :高频事件触发,在定时器内只会执行一次,所以节流会稀释函数的执行效率。
1.拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
2.缩放场景:监控浏览器 resize
3.动画场景:避免短时间内多次触发动画引起性能问题
26.数组去重
indexOf
1 |
|
Set
1 | function newArr(arr){ |
利用递归去重
24.Git指令
git init 初始化git仓库
git status 查看文件状态
git add 文件列表 追踪文件
git commit -m 提交信息 向仓库中提交代码
git log 查看提交记录
覆盖工作目录中的文件: git checkout –文件名
将文件从暂存区中删除: git r m –cached 文件名
git branch 查看分支
git branch 分支名称 创建分支
git checkout 分支名称 切换分支
git merge 来源分支 合并分支 (必须在master分支上才能合并d)
git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)
将本地仓库推送到远程仓库: git push 项目链接
Git 添加远程仓库origin (origin是仓库别名): git remote add 仓库名 项目链接
git push origin master
git push -u origin master
-u 将推送地址和分支保存,下次推送输入git push即可
25.什么是盒子模型?
在我们HTML页面中,每一个元素都可以被看作一个盒子,而这个盒子由:内容区(content)、填充区(padding)、边框区(border)、外边界区(margin)四部分组成。
标准模式下: 一个块的总宽度(页面中占的宽度)= width + margin(左右) + padding(左右) + border(左右)
怪异模式下: 一个块的总宽度= width + margin(左右)(即width已经包含了padding和border值)(IE浏览器)
26.什么是内存泄漏
程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存。
对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
27.原生Ajax的创建过程
1.创建xhr 核心对象
2.调用open 准备发送
3.如果是post请求,必须设置请求头。
4.调用send 发送请求 (如果不需要参数,就写null)
5.监听异步回调
备注:如果是post请求,想要传json格式数据。
28.事件冒泡,事件捕获,事件流
事件冒泡:事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。
事件捕获:事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。
事件流:DOM结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。
29.阻止事件冒泡
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为
还有一种有冒泡有关的:
3.event.preventDefault();
它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为
30.箭头函数与普通函数区别
箭头函数是匿名函数不能作为构造函数不能使用new
箭头函数不绑定arguments,需要用运算符解决…解决
箭头函数不绑定this,会捕获其所在的this值,作为自己的this值
箭头函数通过call()或apply()调用一个函数,只传入了一个参数,对this并没有影响.
箭头函数没有原型属性
31.let、const、var 的区别
var声明的变量存在变量提升,变量可以声明之前调用
let和const不存在变量提升
let和const存在暂时性死区
var允许重复声明变量, let和const在同一作用域不允许重复声明变量
var不存在块级作用域,let和const存在块级作用域.
var和let可以修改声明变量
const声明的变量不能改变一但改变立即初始化,不能留到以后赋值
32.单向数据流和双向绑定
1.Vue 在不同组件间强制使用单向数据流,父组件可以向子组件传递数据,但是子组件不能直接修改父组件的状态。
2.数据的双向绑定
主要由MVVM框架实现,主要由三部分组成View、ViewModel和Model组成,其中view和model不能直接进行通信,他们通过中间件ViewModel来进行通信。
33.图片懒加载
对页面加载速度影响最大的就是图片,一张普通的图片可以达到几M的大小。当页面图片很多时,页面的加载速度缓慢,几S钟内页面没有加载完成,也许会失去很多的用户。
所以,对于图片过多的页面,为了提高加载速度, 我们需要将页面内未出现在可视区域内的图片先不做加载, 等到访问到可视区域后再去加载。这样子对于页面加载性能会有很大的提升,也提高了用户体验。
34.nextTick的理解
使用nextTick的原因:Vue是异步修改DOM的,并且不鼓励开发者直接接触DOM,但是有时候需要必须对数据更改后的DOM元素做相应的处理,但是获取到的DOM数据并不是更改后的数据,这时候就需要this.$nextTick();
原理:Vue通过异步队列控制DOM更新和nextTick回调函数先后执行的方式。
35. for in 与 for of的区别
for of 遍历数组
用于对数组或者对象的属性进行循环操作。
for in 遍历对象
for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象,以及字符串
36.数组操作方法
37.字符操作方法
38.水平垂直居中
1 | <div id="box"> |
方法一:父相自绝后,子分部向左向上移动本身宽度和高度的一半(也可以用 transform:translate(-50%,-50%))最常用方法
1 | #box{ |
方法二:父元素设置成弹性盒,子元素横向居中,纵向居中
1 | #box{ |
方法三:父向子绝,子元素所有定位为0,margin设置auto自适应。
1 | #box{ |
39.null和undefined区别
在JavaScript中,null 和 undefined 几乎相等
null和undefined区别:
null表示没有对象,可能将来要赋值一个对象,即该处不应该有值
undefined表示缺少值,即此处应该有值,但没有定义
40.箭头函数
箭头函数与普通函数区别
箭头函数是匿名函数不能作为构造函数不能使用new
箭头函数不绑定arguments,需要用运算符解决…解决
箭头函数不绑定this,会捕获其所在的this值,作为自己的this值
箭头函数通过call()或apply()调用一个函数,只传入了一个参数,对this并没有影响.
箭头函数没有原型属性