vue的面试题

131 阅读27分钟

1路由懒加载的功能:路由懒加载也叫作延迟加载,使用懒加载可以减少我们第一次打开项目首页的时间,不至于页面出现长时间的白屏,即使添加了开场动画也不好看,而使用懒加载的话就可以减少这样的情况发生,优化用户的体验,如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

  1. vue异步组件
  2. es提案的import()
  3. webpack的require,ensure()

2,什么是package.json

1、通过命令生成的vue项目就包含package.json,这是vue项目的表述文件,依赖包就是根据package.json来安装的。

面试项目重点: 在项目里遇到什么大坑? 把思路理清说出来

我在团队中有什么突出的亮点说出来。

v-model实际上时语法糖,下面就是语法糖的构造过程。

v-model是一个语法糖,实际就是v-bind和v-on的结合体。首先通过v-bind绑定value值给子组件实现单项数据流,子组件再通过emit给父组件传递一个input事件同时携带了emit给父组件传递一个input事件同时携带了event.target.value值给父组件,父组件将获取到的值重新赋给value从而实现数据的双向绑定 (重点)

而v-model自定义指令下包裹的语法是input的value属性、input事件

  • input属性绑定——inputV变量,也就是将值传给input;
  • input事件,该事件在input的值inputV改变时触发,事件触发时给inputV重新赋值,所赋的值是$event.target.value,也就是当前触发input事件对象的dom的value值,也就是该input的值。

这就完成了v-model的数据双向绑定。

我们会发现elementUI的所有自定义组件都适用v-model这一语法糖,除了input之外,select、textarea也用到这一语法糖。
  • text和textarea元素:v-model使用value属性设置初始值并绑定变量input事件更新值
  • checkbox和radio元素:v-model使用checked属性设置初始值并绑定变量,change事件更新值;
  • select元素:v-model使用value属性设置初始值并绑定变量,change事件更新值;

vuex刷新页面后数据就消失了,怎么保存数据。 存到vuex中,同时存一份到sessionstorage中,当刷新页面时,判断sessionstorage中是否存在,存在就直接将sessionstorage中的值取出再存到vuex中去,缺点是sessionstorage的缓存大小仅限于5m内,而且转json时,会容易导致数据缺失,建议存储前,先进行一次加密,获取时再进行解构处理。

原型原型链:1,有了一个函数对象,就有了原型。切记这一点,讨论原型,不能脱离了函数,它是原型真正归属的地方,原型只是函数的一个属性!。2,知道了原型的概念,我们再看看原型链。一般面试官问简单介绍一下原型链时,标准答案基本是:“每个对象都有一个属性_proto_指向它的原型,最终指向null,当访问对象上的属性时,如果找不到,就会寻找_proto_上有没有,找到就返回该属性,否者返回undefined,这样形成的链表型数据结构就是原型链”。

Event Loop是什么

event loop是一个执行模型,在不同的地方有不同的实现。浏览器和NodeJS基于不同的技术实现了各自的Event Loop。

tcp断开连接的四次挥手:1,客户端向服务器请求断开连接 2,服务器表示已经收到了客户端断开连接的请求 3,服务器收到客户端断开连接且已经没有数据需要发送给客户端的时候向客户端请求断开连接 4,服务器表示已经收到了客户端断开连接的请求 结果:至此服务器到客户端的连接关闭 客户端到服务器的连接也关闭了 四次挥手保证了双端正确的断开连接

解释一下生命周期:Vue实例从创建到销毁的过程就是生命周期,就是指从创建、初始化数据、编译模板、挂载DOM到渲染、更新渲染、销毁等一系列过程,他主要分为8个阶段,创建前后、载入前后、更新前后、销毁前、销毁后、以及一些特殊场景的生命周期,接下来我说一下这8个阶段分别做了什么事情。

image.png Created和 mounted的区别: Created:是在组件实例一旦创建完成的时候立即调用,这时候页面dom节点并未生成
Mounted :是在页面dom节点渲染完毕之后就立即执行的created的触发时机要比mounted更早一些
两者的相同点都是可以拿到实例对象的属性和方法,但是如果放在mouted请求有可能导致页面闪动,但如果在页面加载完成则不会会出现此情况。

$nexttick的作用: 1、问题 父组件向子组件传值,父组件值更新,调用子组件方法,方法中拿到的还是旧值。 2、原因 在父组件值改变的方法中,修改传递给子组件的值,直接调用子组件的方法,此时,子组件的dom还未更新,需要等整个父组件(包含子组件)更新完毕后再调用子组件的方法。 3、解决办法 在父组件改变值的方法中使用:

this.nextTick(()=>this.nextTick(()=>{ this.refs.子组件使用标签身上ref的值.子组件的方法() }), 1 2 3 等整个组件DOM更新完毕后(此时子组件接收的父组件的值也更新了)再调用子组件的方法,此时 ,子组件的方法使用的就是父组件传递的最新的值。

keepalive作用:keep-alive 是 vue 内置的组件,用 keep-alive 包裹组件时,会缓存不活动的组件实例,而不是销毁他们。主要用于保存组件状态或避免重复创建。避免重复渲染导致的性能问题。

特点

  • 它是一个抽象组件,自身不会渲染一个 dom 元素,也不会出现在组件的父组件链中。
  • 当组件在 keep-alive 内被切换,组件的 activated 和 deactivated 这两个生命周期钩子函数会被执行。组件一旦被 缓存,再次渲染就不会执行 created、mounted 生命周期钩子函数。
  • 要求同时只有一个子组件被渲染。
  • 不会在函数式组件中正常工作,因为它们没有缓存实例

### 1.1. 认识插槽slot

在开发中,我们会经常封装一个个可复用的组件:

  • 但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素;
  • 比如某种情况下我们使用组件希望组件显示的是一个按钮,某种情况下我们使用组件希望显示的是一张图片;
  • 我们应该让使用者可以决定某一块区域到底存放什么内容;

举个栗子:假如我们定制一个通用的导航组件 - NavBar

  • 这个组件分成三块区域:左边-中间-右边,每块区域的内容是不固定;
  • 左边区域可能显示一个菜单图标,也可能显示一个返回按钮,可能什么都不显示;
  • 中间区域可能显示一个搜索框,也可能是一个列表,也可能是一个标题,等等;
  • 右边可能是一个文字,也可能是一个图标,也可能什么都不显示;

这个时候我们就可以来定义插槽slot:

  • 插槽的使用过程其实是抽取共性、保留不同;
  • 我们会将共同的元素、内容依然在组件内进行封装;
  • 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;

es6常见语法: 一,var let const区别

  1. var 声明的变量作用域在所处的函数内,let 和 const 声明的变量作用域在所处的大括号内。
  2. var 声明的变量存在变量提升现象,let 和 const 声明的变量不存在变量提升现象。
  3. const 声明变量时必须要赋值,赋值之后不能再重新赋值。

二,箭头函数 ...

三,解构赋值:解构就是把数据结构进行分解,然后赋值给定义的变量

四,set:Set 是 ES6 提供的一种数据结构,它和数组很像,但是它里面的数据是不可重复

五,模板字符串

**如何理解重排和重绘: 重排就是当页面的结构发生变化了,就会重排,比如改变变字体的大小,增删 DOM 元素这样的。重绘就是页面结构没有变化,只是外观变了,比如改了一下字体颜色、背景颜色这样的。就只会发生重绘。重排一定会导致重绘,重绘不一定导致重排

解释下rem:rem是css3的一个相对单位,rem可以成比例的调正字体的大小。用途:在需要适配多端设备的话使用rem

媒体查询 不同端的设备下,在css文件中,1px所表示的物理像素的大小是不同的,因此通过一套样式,是无法实现各端的自适应。由此我们联想:

如果一套样式不行,那么能否给每一种设备各一套不同的样式来实现自适应的效果?

答案是肯定的。

使用@media媒体查询可以针对不同的媒体类型定义不同的样式,特别是响应式页面,可以针对不同屏幕的大小,编写多套样式,从而达到自适应的效果。

BFC 全称:Block Formatting Context, 名为 "块级格式化上下文"。

W3C官方解释为:BFC它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用,当涉及到可视化布局时,Block Formatting Context提供了一个环境,HTML在这个环境中按照一定的规则进行布局。

简单来说就是,BFC是一个完全独立的空间(布局环境),让空间里的子元素不会影响到外面的布局。那么怎么使用BFC呢,BFC可以看做是一个CSS元素属性

什么是跨域: 了解跨域首先要了解同源策略,同源策略是指两个url地址的域名,端口和协议相同,不相同的话就形成了跨域。跨域简单来说就是我请求的接口地址和打开的网址不同源,就是跨域 解决跨域有几种方法,1,cors让后端设置项目头。2,jsonp,利用前端的script标签发送请求没有跨域限制来获取数据 。限制:利用script标签发送请求只支持get请求,不支持post请求。3,nginx反向代理 4,proxy(只能在本地开发环境中生效,上线就失效了,dist文件直接放到后端服务器中)

vue双向绑定原理:当生成一个vue实例时,会先去用object.defineProperty()来截取属性的getter和setter,当数据变化时会触发setter,setter会触发dep订阅搜集相对于属性的所有更新方法。

最近的项目介绍: 我最近的做的项目是是个后台管理系统,这个后台管理系统主要是对电商平台的数据展示数据维护,是给内部人员开发的一个管理平台,内容人员可以对里面的商品进行添加删除操作,可以添加用户和修改权限的操作。 这个项目所用到的技术栈有 vue ,vue-router,axios,vuex,echarts和elementui , 我在这个项目里主要是负责登录模块,用户权限模块和商品管理模块,登录模块:用户在登录的时候输入账号和密码通过请求登录接口返回token和用户信息,返回的token值我是放在了sessionStorage中。在这个项目里对axios进行二次封装,其中封装了axios请求拦截器axios.interceptors.request.use ,在请求拦截器中将登录获取到的token值保存到请求头中以方便每天请求都携带token,和响应拦截器axios.interceptors.response.use以便于对服务器返回的数据进行修改操作。在用户权限模块我是先获取用户权限列表渲染用户权限,然后实现分配用户权限的功能,利用elementui的el-tree组件对用户的权限以树状图的形态进行展示,并根据需求封装了递归函数,对每个用户的权限进行递归循环处理,将用户权限目录转换成树形结构的数据展示出来。我还负责项目的商品分类模块,首先请求商品分类的接口获取数据,利用elementui的级联选择器cascader对获得的数据进行渲染,通过cascader的props属性对渲染规则进行配置,使v-model绑定分类id,当点击分类时携带指定分类的id请求接口获取分类的动态参数和静态属性的分类。

vue的双向绑定原理: vue数据的双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。其核心就是通过Object.defineProperty()方法设置set和get函数来实现数据的劫持,在数据变化时发布消息给订阅者,触发相应的监听回调。也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;

EventBus的简介

EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的灾难,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。

for in 和 for of 简单来说就是它们两者都可以用于[遍历],不过for in遍历的是数组的索引(index),而for of遍历的是数组元素值(value)

BFC:块级格式化上下文

理解:BFC属于普通流,相当于一块独立的渲染区域,BFC看成是元素的一种属性, 当元素拥有了BFC属性后,这个元素就可以看做成隔离了的独立容器。容器内的元素不会影响容器外的元素.

防抖节流: 防抖:防抖是指在事件触发n秒后再执行[回调],如果在n秒内再次被触发,则重新计算时间。 2、节流:节流是指如果持续触发某个事件,则每隔n秒执行一次。

em、rem的区别:

rem与em都是相对单位,我们使用它们的目的就是为了适应各种手机屏幕。

rem是根据html根节点来计算的,而em是继承父元素的字体。

对于em和rem的区别一句话概括:em相对于父元素,rem相对于根元素。

v-if用在只显示一次的地方 比如一套系统 有管理员有用户 登录完呈现不同的状态。 v-show比如登录框里面的校验密码是否正确的提示框就应该v-show

Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实DOM,进而提高效率

路由用户鉴权:前端有一份动态路由表,等到用户登录拿到用户的角色之后根据当前登录用户的角色去筛选出可以访问的路由,形成一份定制路由表,然后动态挂载路由。这样做的好处就是,前端每开发一个页面不需要让后端再去配一下路由和权限了,

通过带有 token 请求头的请求方法,后端可以判断到是哪一个用户,前端也可以通过获取权限接口获得该用户的权限列表,根据权限列表做一份路由映射表,如果后端返回的数据结构与前端的路由设置的数据结构不同,此时还需编写此映射路由的业务功能函数。如果该用户拥有此路由权限,则通过在全局路由监控中 router.beforeEach 进行 router 中的 addRoutes 方法将有权限的路由配置添加到路由当中,侧边栏也可根据路由列表中的 meta 字段中关键字的判断进行相应的渲染。如果权限的颗粒度小到一个按钮,则可根据后端返回的权限列表映射出的权限参数,通过 v-if 进行判断该功能组件是否渲染。
在路由管理中通过 router.beforeEach 钩子中判断当前的路由权限是否为空,是的话则可执行获取权限路由的接口:

CDN 的工作原理 就是将源站的资源缓存CDN各个节点上,当请求命中了某个节点的资源缓存时,立即返回客户端,避免每个请求的资源都通过源站获取,避免网络拥塞、缓解源站压力,保证用户访问资源的速度和体验

session,token,cookie的区别和作用:

image.png

echars基本图解: 1653320903(1).png

简单介绍一下vue-router以及它的作用: vueRouter是vue.js官方的路由管理器。它和vue.js的核心深度集成,让构建单页面应用变得易如反掌。vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。

JSON.stringfy()和JSON.parse()的作用:

平时我们在接收后端返回的json对象通常是一个字符串类型的object,所以一般我们要对这个object进行类型转化后,我们才能使用object里面的数据,而这其中涉及到两个必不可少的方法就是JSON.parse和JSON.stringify

Vue key的作用: 总结: key 就是给 虚拟 dom 添加了一个 标识, 优化了对比策略!!!

  1. vue 的更新机制 (差异化更新) 对比新旧虚拟 dom, 找出不同的部分, 进行更新视图

    为什么对比虚拟 dom, 而不对比真实的 dom ? 真实的 dom 太复杂, 对比起来性能太差

  2. 虚拟 dom: 使用 js 对象的方式, 模拟真实的 dom 结构 { type: 'div', className: 'box' , children: [] }

    属性的量大大的减少了, 没有真实 dom 的那么多无效的属性, 对比起来性能高很多

  3. diff 算法: 默认的对比(diff) 机制, 同层兄弟元素, 是按照下标进行对比的, 但是加了 key, 就相当于给虚拟 dom 加了个标识

    对比策略, 就是对相同 key 的元素进行对比了, 在列表 v-for 中, key 的使用尤为常见, 可以用于优化渲染性能

3. 总结

推荐使用数据的唯一标识作为key,比如id,身份证号,手机号等等,通常这些数据由后端提供。

后续操作不破坏原来数据顺序的话,使用index作为key也没有任何问题。

  1. key的实现原理 要解释key的实现原理,就要引入Vue一个十分重要的概念——【虚拟DOM】。

    给出一组数据,Vue要把这些数据渲染到页面上,首先要生成【虚拟DOM】,然后根据【虚拟DOM】去生成【真实的DOM】。如果数据发生了改变,Vue会生成【新的虚拟DOM】,注意,这个【新的虚拟DOM】并不会直接生成【新的真实DOM】,否则虚拟DOM一点用处也没有了。Vue的操作是,拿根据新的数据生成的【新的虚拟DOM】与之前的【真实的DOM】去做比较,如果相同,直接延用即可(“拿来主义”);如果不同,则生成新的DOM对象。

v-for优先级比v-if高,如果出现在一个dom上,循环后并判断条件就会浪费资源还可能报错,最好在外层套一个div放for循环里面放if

JS Event Loop (事件循环 ) JS是单线程语言,JS Event Loop(事件循环)用于处理异步多线程 宏任务和微任务:都是异步任务,但执行顺序不同 宏任务执行之前,必须保证微任务队列是清空的,如果不为空,优先执行微任务队列中的任务(回调) 宏任务:定时器,事件,new promise,await的返回内容 微任务:.then(),nextTick,await语句之后的函数体 1.将普通函数依次压入调用栈中,依次执行,执行完成后弹出 2.遇到宏任务,会压入到消息队列中,等调用栈微任务队列清空后执行

为什么使用CDN

Vue项目打包的时候,默认会把所有代码合并生产新文件,其中包括各种库导致打包出来很大。如果使用cdn的话,会更利于程序的加载速度。

在Vue项目中,引入到工程中的所有js、css文件,编译时都会被打包进vendor.js,浏览器在加载该文件之后才能开始显示首屏。若是引入的库众多,那么vendor.js文件体积将会相当的大,影响首开的体验。

解决方法

将引用的外部js、css文件剥离开来,不编译到vendor.js中,而是用资源的形式引用,这样浏览器可以使用多个线程异步将vendor.js、外部的js等加载下来,达到加速首开的目的。

外部的库文件,可以使用CDN资源,或者别的服务器资源等。

使用CDN主要解决两个问题

  1. 打包时间太长、打包后代码体积太大,请求慢
  2. 服务器网络不稳带宽不高,使用cdn可以回避服务器带宽问题
# JS_常用数组方法汇总

>包含数组转字符串、数组堆栈、数组排序、数组拼接、数组删改、数组索引、创建数组、数组循环遍历等方法

# 数组转字符串方法

## split()

>可以把一个字符串切割成数组

### 参数

>参数1:可选参数,从指定位置切割
>
>参数2:可选参数,指定返回的数组长度

## join()

>可以把数组内的所有元素放入一个字符串
>
>元素通过指定分隔符分隔

### 参数

>参数1:可选参数,传入指定的分隔符,默认为','

# 数组堆栈方法

## push()

>向数组的末尾添加一个或多个元素,并返回新的长度【会改变原数组】

## pop()

> 删除数组的最后一个元素【会改变原数组】

## unshift()

> 将新项添加到数组起始位置【会改变原数组】

## shift()

> 用于把数组的第一个元素从其中删除,并返回第一个元素的值【会改变原数组】

## arr.length属性

> 可直接于数组长度+1,追加元素

### 示例代码

```js
const arr = [1,2]
arr[arr.length] = 3
```

# 数组排序方法

## reverse()

> 反转原数组元素顺序,返回值是倒序后的原数组【会改变原数组】

## sort()

>用于对数组的元素进行排序,返回值是重新排序后的原数组【会改变原数组】
>
>使用数字排序,须通过一个函数作为参数来调用
>
>升序(a-b)
>
>降序(b-a)

### 实现随机排序_示例代码

```js
function randomsort(a, b) {
  return Math.random()>.5 ? -1 : 1
  //通过随机产生0到1的数,然后判断是否大于0.5从而影响排序,产生随机性的效果。
}
var arr = [1, 2, 3, 4, 5]
arr.sort(randomsort)
```

# 数组拼接方法

## concat()

>可用于拼接数组,也可传入数组,会把数组元素取出并拼接
>无法拼接多维数组,返回一个新数组

## ES6展开拼接

```js
[...arr,...arr2] 
```

# 数组删改方法

## slice()

>选择数组的一部分,并返回【新数组】

### 参数

> start,end,参数无法交换位置,不传参数则拷贝原数组
>
> 截取规则: [),左闭右开,从左开始在右前停止,例如:
>
> ```js
> const arr = [1,2,3,4,5]
> 
> arr.slice(2,4) // 3,4
> ```
>
> 作用2:
>
> 将字符串转为数组
>
> ```js
> Array.prototype.slice.call(str)
> ```

## splice()

> 从数组中添加/删除元素组成的数组,返回值是添加/删除元素组成的数组,没有添加/删除的话返回空【会改变原数组】

### 参数

> 1.必选参数,index,规定从何处添加/删除元素
>
> 2.可选参数,规定应该删除元素的个数/长度【区别于slice()的下标左闭右开】,可以为0,如未填写参数,则删除从index到数组结尾所有元素
>
> 3.可选参数,想要添加到数组的新元素

## fill()

> 填充,将一个固定值替换数组的元素,闭合位置同样遵循【左闭右开】【会改变原数组】
>
> Es6方法

### 参数

> 1.必需参数,填充值
>
> 2.可选参数,开始填充位置
>
> 3.可选参数,停止填充位置

# 数组索引方法

## indexOf()

> 可返回数组中某个指定的元素首次出现的索引

### 参数

> 1.必选参数,检索内容
>
> 2.可选参数,开始检索的位置

## lastIndexOf()

> 同indexOf()方法,不过查找方向相反

## includes()

> 用来判断数组是否包含一个指定的值,包含返回true,否则false

## find()

> 返回数组中第一个符合条件的元素的值,如果没有符合条件的元素返回 -1

### 参数

> 1.必选参数,回调函数
>
> 2.可选参选,传递一个对象作为该回调函数的this指向,如果这个参数为空,"undefined"会传递给"this"

## findIndex()

> 返回数组中第一个符合条件的元素的索引,如果没有符合条件的元素返回 -1

### 参数

> 1.必选参数,回调函数
>
> 2.可选参选,传递一个对象作为该回调函数的this指向,如果这个参数为空,"undefined"会传递给"this"

## at()

>at() 方法接收一个整数值并返回该索引的项目,允许正数和负数
>
>ES2022

### 参数

>要返回的数组元素的索引(位置)。当传递负数时,支持从数组末端开始的相对索引;也就是说,如果使用负数,返回的元素将从数组的末端开始倒数。

# 创建数组方法

## Array.of()

> 【ES6】创建数组,参数及为数组元素
>
> ES5使用new Array()构造数组的时候,会有歧义
>
> Array(3),当参数只有一个时,创建length为3的空数组
>
> Array(3,4,5),当参数大于两个时,将参数连接创建为数组,会有歧义
>
> 静态方法,于构造器内部,只能通过Array调用

## Array.from()

> 【ES6】将类数组对象转为真正的数组对象,也是Es6对于之前处理方式的优化
>
> Es6之前,需要使用Array.prototype.slice.call(str)将类数组转化为数组
>
> ...数组展开实际上就是对Array.from()的封装
>
> Array.from()方法转出的对象,为克隆出来的深拷贝对象
>
> 静态方法,于构造器内部,只能通过Array调用

### 示例代码

```js
console.log(Array.from(arr) === arr) // false 深拷贝
```

## keys()

> 【ES6】返回一个新的【数组迭代器】对象,该对象包含数组中每个索引的键,可用循环遍历该对象
>
> 原型方法
>
> Object对象原型上也有该方法,是静态方法,需要通过Object调用

## values()

> 【ES6】返回一个新的【数组迭代器】对象,该对象包含数组中每个索引的值,可枚举,可用循环遍历该对象
>
> 原型方法
>
> Object对象原型上也有该方法,是静态方法,需要通过Object调用

## entries()

> 【ES6】返回一个新的【数组迭代器】对象,该对象包含数组中每个索引的键值对,可枚举,可用循环遍历该对象
>
> 原型方法
>
> Object对象原型上也有该方法,是静态方法,需要通过Object调用

# 数组循环遍历方法

## forEach()

>用于调用数组的每个元素,并将元素传递给回调函数
>
>forEach()方法没有返回值,无法跳出循环

### 参数

>1.必选参数,数组中每个元素都会调用的回调函数,函数参数:item【当前元素】,index【当前索引】,arr【当前遍历数组本身】
>
>2.可选参选,传递一个对象作为该回调函数的this指向,如果这个参数为空,"undefined"会传递给"this"

### 示例代码

```js
// forEach方法的第二个参数
const arr = [1,2,3]
const out = []

arr.forEach(function(item){
    this.push(item)
},out) // 改变this为out,调用out原型push方法

const obj = {
    name: 'obj',
    number: [0,1,2,3,4,5,6,7,8,9],
    print(){
        console.log(this) // obj
        this.number.forEach(function(){
            console.log(this) // 原先为window
        },this) // obj,也可用箭头函数绑定外部作用域this
    }
}
obj.print()
arr.forEach(function(){
    console.log(this) // arr
},arr)
```

### 注意

> 1.forEach()方法会忽略稀疏数组中为空的元素[1,,3],跳过执行,不会调用forEach方法
> 即,稀疏元素不具有迭代器
>
> ```js
> // 稀疏数组
> delete arr[1] // delete方法删除数组元素也会创建稀疏数组
> console.log(arr.length)
> ```
>
> 2.类数组对象无法遍历
>
> 但可通过call去强行指定
>
> ```js
> Array.prototype.forEach.call(argument,function(){...})
> ```
>
> 3.遍历方法对于空数组不会执行回调,因为其内部没有迭代器

## map()

> 返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值
>
> 呈映射关系

### 参数

> 1.必选参数,数组中每个元素都会调用的回调函数,函数参数:item【当前元素】,index【当前索引】,arr【当前遍历数组本身】
>
> 2.可选参选,对象作为该执行回调时使用,传递给函数,用作"this"的值,如果省略,或者传入null、undefined,那么回调函数的 this 为全局对象

## filter()

> 创建一个新的过滤数组,新数组中的元素是通过检查指定数组中符合条件的所有元素

### 参数

> 1.必选参数,数组中每个元素都会调用的回调函数,函数参数:item【当前元素】,index【当前索引】,arr【当前遍历数组本身】
>
> 2.可选参选,对象作为该执行回调时使用,传递给函数,用作"this"的值,如果省略,或者传入null、undefined,那么回调函数的 this 为全局对象

### 拓展

> 1.Number.isInteger()方法
>
> 用来判断给定的参数是否为整数,除此之外,都是返回false(NaN或Infinity,空串等也是)
>

## some()

> 用于检测数组中的元素是否满足指定条件
>
> 如果【有一个】元素满足条件,则表达式返回true,剩余的元素不会再执行检测
>
> 如果没有满足条件的元素,则返回false
>
> 不会对空数组进行检测

### 参数:

> 1.必选参数,数组中每个元素都会调用的回调函数,函数参数:item【当前元素】,index【当前索引】,arr【当前遍历数组本身】
>
> 2.可选参选,对象作为该执行回调时使用,传递给函数,用作"this"的值,如果省略,或者传入null、undefined,那么回调函数的 this 为全局对象

## every()

> 用于检测数组【所有元素是否都符合指定条件】
>
> 如果数组中检测到有一个元素不满足,则整个表达式返回false,且剩余的元素不会再进行检测
>
> 如果所有元素都满足条件,则返回true
> 不会对空数组进行检测

### 参数:

> 1.必选参数,数组中每个元素都会调用的回调函数,函数参数:item【当前元素】,index【当前索引】,arr【当前遍历数组本身】
>
> 2.可选参选,对象作为该执行回调时使用,传递给函数,用作"this"的值,如果省略,或者传入null、undefined,那么回调函数的 this 为全局对象

### 与some()的区别

> every()相当于&&,需要全部数组元素都满足条件才返回true

\

我最近的做的项目是是个ctrm风险管理系统,这个后台管理系统主要是对风险管理平台的数据展示数据维护,是给内部人员开发的一个管理平台,内容人员可以通过工作台看到当前市场的快讯和前端产品的动态(利用websocket技术获取接口数据),管理员可以添加员工账号并赋予员工一定的权限。 这个项目所用到的技术栈有 vue ,vue-router,axios,vuex,echarts和elementui,websocket , 我在这个项目里主要是负责登录模块,员工权限模块和期货数据展示模块,登录模块:用户在登录的时候输入账号和密码通过请求登录接口返回token和用户信息,返回的token值我是放在了sessionStorage中。在这个项目里对axios进行二次封装,其中封装了axios请求拦截器axios.interceptors.request.use ,在请求拦截器中将登录获取到的token值保存到请求头中以方便每天请求都携带token,和响应拦截器axios.interceptors.response.use以便于对服务器返回的数据进行修改操作。在用户权限模块我是先获取用户权限列表渲染用户权限,然后实现分配用户权限的功能,利用elementui的el-tree组件对用户的权限以树状图的形态进行展示,并根据需求封装了递归函数,对每个用户的权限进行递归循环处理,将用户权限目录转换成树形结构的数据展示出来。在这个项目我还负责期货数据展示模块,由于展示的是期货数据,数据是在很短的时间内就要更新的,这个时候如果只是简单的请求接口获取数据的话,每次需要数据更新的时候我还要点击刷新数据才能更新,这个时候就需要用到websocket协议用来实现数据无刷更新的功能,这个模块主要是主要echarts框架和websocket双向通信协议,这里我用到了echarts的矩形树图,首先是请求数据接口获取到数据之后,使用map方法遍历数据并修改数据中的某个值,修改好后定义一个变量把数据赋值给变量,同时建立websocket请求,设置请求体,使用sendwebsocket方法放入请求体请求数据,请求回来的数据和之前使用接口获取的数据做对比判断,分别循环这两个数据并对比这个两个数据的某个字段,如果字段相同的话就将websocket获取的新数据填充之前使用接口获取的数据以达到不刷新更新数据的功能,