面试记录

221 阅读14分钟

第一家面试记录

1、项目介绍? ... ...

2、事件循环?

**解释:**单线程非阻塞的脚本语言,单线程是一时间只能做同一件事,非阻塞是代码进行一个异步任务的时候,在这个任务返回结果的时候根据结果去执行相应回调。

**执行机制:**所有任务都在主线程上,形成一个执行栈。主线程外还有一个任务队列。先执行栈中的同步任务,异步任务放到任务队列中。同步任务执行完毕,再依次读取任务队列的异步任务,这时异步任务结束等待状态,进入执行栈开始执行。先执行准备好的微任务,然后再执行宏任务。栈不断获得任务、执行任务、获取任务、再执行的机制。

异步队列又分为:宏任务和微任务,因为宏任务的执行时间较长,所以微任务优于宏任务。

  • 宏任务:setTimeout、setInterval、I/O文件操作、setImmediate中断长时间运行的操作、Ajax 请求、script代码**;**

  • 微任务:.then、.catch .finally、process.nextTick、async\await;

3、路由守卫?

**全局路由守卫:**在整个页面中,只要路由发生了变化都会触发,一般写在路由配置文件。路由在真正跳转前, 会执行一次beforeEach函数,next调用则跳转,也可以强制修改要跳转的路由。

主要包含两个函数:

  • 前置守卫:router.beforeEach(fn) :to\from\next()

  • 后置守卫:router.afterEach(fn):to\from,路由完成的回调

  • 解析守卫:router.beforeResolve(fn):to\from\next()

**参数:**to:目标路由对象;from:即将要离开的路由对象;next():放行

4、路由模式?(Vue的路由实现模式?)

  1. **hash模式:**在浏览器中 # 号后面的字符称之为hash,用 window.location.hash 读取。特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重新加载页面。

  2. **history模式:**history采用HTML5的新特性;且提供了两个新方法: pushState(), replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。

5、获取hash模式#后面的值?

  • window.location.hash
  • getUrlHashParams(paramName: string)
  • lastIndexOf+slice

6、let const 区别?

  1. 污染全局、块级作用域、重复声明、暂时性死区(先使用后声明中间会出现)

  2. var 可以重复声明变量,不受限于块级;有变量提升,可以在声明的上面访问变量,提升到作用域的最顶端,但访问结果是undefined;挂载到全局window;

  3. let:声明变量,只能在(块级)作用域内使用,先使用后声明会出现死区,不能重复声明;

  4. const 声明常量,用于定义不可修改的值(定义引用数据类型是在堆里面,对象可以修改,数组push的话可以修改)s,声明之后必须初始化赋值,支持块级作用域;

7、vuex和localStorage存储token?

token在本地存储放一份是为了持久化存储,同时vuex也要保存一份,vuex是响应式。

用 vuex保存token是为了每个组件都可以访问, 但vuex有一个缺点 就是刷新页面vuex中的数据会清空,这要导致只要用户一登录 并且刷新 保存的token就会消失,为了解决这个问题 我们要把token存在localStorage。 

8、怎么解决token过期?

token的过期时间是由后端来决定的,前端如果想知道token有没有过期,需要根据后端返回的状态码来判断,如果状态码为401则表示 token过期,token过期之后我们需要调用退出登录方法,并且将本地和vuex里面存储的token进行清除 。

  1. 刷新令牌(Refresh Token):在许多应用中,除了访问令牌(Access Token)之外,还有一个刷新令牌。当访问令牌过期时,可以使用刷新令牌获取新的访问令牌,而不需要重新登录。这种方法可以提高用户体验,因为用户不需要在每次令牌过期时重新输入用户名和密码。
  2. 自动重登:一些应用会在检测到用户登录状态失效后自动尝试重新登录,并在重登成功后自动刷新令牌。这种方法可以减少用户的干预,但可能会对用户体验产生一定影响,因为用户可能会在非预期的情况下被重登。
  3. 手动刷新:用户可以手动刷新令牌。在应用中提供一个“刷新令牌”的选项,用户可以手动触发令牌刷新操作。这种方法需要用户具备一定的操作能力,但对于一些特定场景(如企业应用)来说可能是必要的。
  4. 使用OAuth 2.0:OAuth 2.0是一种身份验证协议,它允许用户将身份验证和授权委托给第三方应用。通过使用OAuth 2.0,用户可以在一次登录后多次授权第三方应用访问其资源,而不需要每次都输入用户名和密码。这种方法可以提高用户体验和安全性。

9、箭头函数和普通函数的区别? 

注意:主要是this指向的问题

箭头函数:

  • 是匿名函数,不能使用构造函数和new。

  • 没有this沿用上级作用域this;外层没有就是window。

  • 没有原型属性。

  • argument 参数

  • 通过call或apply调用函数时,只传一个参数对this没有影响。

10、 this指向?

  • 函数调用时: this 指向 window;

  • 方法调用时: this 指向调用方法的对象;

  • 构造函数调用时: this 指向新创建的那个对象;

  • 使用 call 和 apply 调用时: this 是指定的那个对象;

  • 箭头函数: 指向外层函数的 this;

  • 特殊情况: this 指向为最后调用它的对象 ;

11、原型?原型链? 

  1. **原型:**原型也是一个对象,通过原型实现对象的属性继承,函数中prototype属性这个对象包含了所有实例共享的属性和方法。prototype属性指向的那个对象叫做原型对象。

  2. **原型的作用:**共享的属性和方法;把不变的方法定义在原型对象上节约内存

  3. **原型链:**当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的_ _ proto _ _隐式原型上查找,即它的构造函数的 prototype,如果还没有找到就会再在构造函数的 prototype 的 __ proto __中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链;

12、数据类型有哪些?怎么相互转化?判断数据类型的方法?

简单型数据类型:数值Number、字符串String、布尔Boolean、空Null、未定义Undefined

复杂性数据类型:数组Array、对象Object、函数Function、正则、日期Data

隐式转换、显示转换:Number(), String(), Boolean(), Object()

强制类型转换:可以使用操作符如+-来强制转换数据类型

13、判断数据类型的方法?

  • **typeof :**判断简单类型和函数,复杂类型均为object。

  • **instanceof:**判断复杂类型,不能区别undefined和null,可以检测多层继承关系。用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

  • **Object.prototype.toString.call:**判断所有数据类型。

  • constructor:不能检测null和undefined

14、vue生命周期? 

  • beforeCreate:初始化
  • created:实例创建完成后被立即调用,data中的数据和方法,未挂载可以访问;
  • beforeMount:挂载开始之前:可以发起服务端请求,请求数据;
  • mounted: 挂载到实例上去之后调用,此时可以操作DOM;(注意:并不能确定子组件被全部挂载,如果需要子组件完全挂载之后执行操作可以使用$nextTick)
  • beforeUpdate:数据更新时调用,发生在虚拟 DOM 打补丁之前;
  • updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁;
  • beforeDestroy:实例销毁之前调用;
  • destroyed:Vue 实例销毁后调用;Vue 实例解绑,事件监听移除,子实例被销毁;

注意:第一次加载页面会触发:beforeCreate, created, beforeMount, mounted

15、优化打包体积?

  • 使用高版本的 Webpack4;
  • 提取公共代码进行封装;
  • 懒加载;CDN加速;(生产环境)
  • loader添加一些匹配规则,快速匹配;
  • 利用缓存提升二次构建速度;
  • 压缩代码图片base64;
  • 多线程/多实例构建;热更新;(开发环境)
  • 缩小打包作用域;
  • Tree shaking 删除死代码;
  • Scope hoisting 作用域提升;
  • 注意:**Webpack4:**for of替代forEach;Map和Set替代Object;includes替代indexOf;默认使用更快的md4 hash算法;使用字符串方法替代正则表达式;

16、优化首屏加载速度?

  • 优化图片和资源文件:压缩图片、优化 CSS 和 JavaScript、使用 CDN。

  • 按需加载资源:使用动态导入、按需加载,可以减少初始加载时间。

  • 懒加载:对于非首屏内容,如侧边栏或底部导航栏,可以使用懒加载技术延迟加载它们。这可以通过将内容包装在 v-ifv-show 指令中实现。

  • 使用预加载和预获取:使用 <link rel="preload"><link rel="prefetch"> 预加载资源,以确保在需要时快速加载它们。

  • 使用服务端渲染(SSR):通过服务端渲染(Server-Side Rendering)预先生成 HTML 输出,可以在客户端渲染之前提供部分内容。这可以加快首屏的加载速度。

  • 优化路由懒加载:使用 Vue Router 的懒加载功能,按需加载路由组件,减少初始加载时间。

  • 优化数据获取:减少不必要的 HTTP 请求;使用分页或滚动来逐步加载数据。

  • 使用性能分析工具: Lighthouse 或 Google Chrome DevTools来进行优化。

  • 减少不必要的依赖和库:

17、小程序支付实现流程?

  1. 调用微信支付统一下单API,生成预支付交易单。
  2. 将预支付交易单的json数据返回给小程序前端。
  3. 小程序前端调用wx.requestPayment接口发起支付请求。
  4. 用户完成支付后,微信服务器会向小程序发送支付结果通知。
  5. 小程序前端调用wx.requestPayment接口发起支付请求时,需要将服务器地址(即上述第4步中的服务器地址)作为参数传入,以便接收支付结果通知。

具体使用的API接口如下:

  1. wx.requestPayment:用于发起支付请求。需要传入以下参数:

    • timeStamp:时间戳,字符串类型,格式为"13位毫秒级时间"。
    • nonceStr:随机字符串,长度要求在32~64个字符之间。
    • package:统一下单API返回的prepay_id参数值,字符串类型。
    • signType:签名方式,默认为"MD5"。
    • paySign:签名,字符串类型。
  2. wx.onPaymentResultNotify:用于接收支付结果通知。当微信服务器向小程序发送支付结果通知时,会触发该函数。需要传入以下参数:

    • appId:小程序的appId。
    • timeStamp:时间戳,字符串类型,格式为"13位毫秒级时间"。
    • nonceStr:随机字符串,长度要求在32~64个字符之间。
    • package:统一下单API返回的prepay_id参数值,字符串类型。
    • signType:签名方式,默认为"MD5"。
    • paySign:签名,字符串类型。

18、服务器渲染和页面渲染概念?优缺点? 

  • **服务器渲染(Server-Side Rendering,SSR):**在服务器端执行页面渲染的过程。具体来说,当用户请求一个网页时,服务器会根据用户的请求内容,查询相应的数据,然后结合HTML模板,生成包含指定信息的HTML文本,最后将这个HTML文本返回给浏览器端。浏览器接收到这个HTML文本后,直接解析并展示页面内容,而不需要再通过JavaScript脚本的执行来生成DOM树和渲染页面。服务器渲染的优点包括更好的SEO(搜索引擎优化),因为搜索引擎爬虫可以直接抓取完全渲染的页面;首屏加载更快,因为用户可以直接看到完整的HTML页面,而不需要等待JavaScript脚本的执行和页面渲染。
  • **页面渲染则:**是将数据和模板拼接在一起,生成最终的HTML页面的过程。这个过程可以在服务器端进行(即服务器渲染),也可以在客户端进行(即客户端渲染)。在客户端渲染中,当用户请求一个网页时,服务器会返回一个空的HTML页面,或者只包含一些基本的布局和占位符。然后,浏览器会执行JavaScript脚本,根据数据和模板动态生成DOM树,并将DOM树渲染成最终的页面。客户端渲染的优点包括更好的用户体验,因为页面交互和数据更新可以通过异步请求实现,不需要重新加载整个页面;同时,客户端渲染也可以减轻服务器的压力,因为服务器只需要返回基本的数据和模板,而不需要处理复杂的页面渲染逻辑。

19、登录功能实现? 

  • 点击登录按钮获取到输入框输入的账号与密码 
  • 调用登录接口将获取到的用户名和密码发送给后台 
  • 登录成功之后后台会返回用户信息以及token 
  • 将token和用户信息保存到vuex和本地
  • 跳转到主页面

20、权限分配实现?

权限控制采用的是RBAC权限模型,相比较于传统的权限设计,他在用户和权限之间多了一个中间层——角色。也就是说,需要给用户分配角色,给角色分配权限 给用户分配角色。

这里会大量使用到Element-ui里面的Dialog组件,所以把这个Dialog组件单独写到一个vue文件里边。里面放置所有角色,这个角色列表是从后端获取的,我们只需要在api目录下定义好接口,调用获取并放到一个空数组中,然后循环该数组在Dialog组件里面渲染出来就可以了。同样的,获取当前用户的角色,基本一样,根据当前用户的id得到当前用户的角色进行渲染。

 接下来就是把修改好的用户角色提交给后端,就是Dialog组件中的确定和取消的事件绑定。通过绑定事件,调用接口,把数据传递给后端。这里用到了父子组件的双向绑定传值,比如说父组件中的修饰符.sync,子组件中的this.$emit('update:方法名') 权限点管理,在api下新建permission.js,在里面封装权限管理的增删改查请求。需要把获取的权限数据转化为树形表格,就在utils下面定义一个转化为树形结构的函数。因为这个函数可能要复用,所以就在main.js中全局注册。

 接下来在侧边栏部分对处理好的vuex中的路由进行渲染,vuex刷新后消失的问题,可以从本地存储中区数据。通过前置路由守卫获取本地存储的token,想要进入其他页面。 因为有功能权限问题,所以用到了mixin方法来查找权限点。

第二家面试记录:

1、项目介绍?

2、有没有单独搭建过项目?

3、登录实现的步骤? 

  1. 点击登录按钮获取到输入框输入的账号与密码
  2. 调用登录接口将获取到的用户名和密码发送给后台
  3. 登录成功之后后台会返回用户信息以及token
  4. 将token和用户信息保存到vuex和本地
  5. 跳转到主页面

4、数组去重的方法? 

set、双重for循环、sort、set + includes、for + splice、Map、reduce

5、深拷贝浅拷贝的区别?怎么实现? 

**深拷贝:**创建新的内存地址存放复制的地址;把数据完全克隆一份给另个地址;

实现方法:

  1. js库 lodash: _.cloneDeep(obj)

  2. 通过序列化实现:JSON.parse(JSON.stringify(obj)),普通对象

  3. 递归代码实现过程

    • 拷贝的数据以参数的形式传参

    • 声明一个变量 来储存我们拷贝出来的内容

    • 通过 instanceof 判断旧对象数据类型,如果是基本类型就直接赋值

    • 是引用类型数据 对象和数组的话,创建空数组[ ]或空对象 { }

    • 循环对象中的每一项,再判断有没有引用数据类型,有再递归调用没有直接赋值

    • 赋值完毕, return赋值后的新对象

**浅拷贝:**对象的地址拷贝给新对象;原地址对象改变,拷贝的对象也会改变;

  • ... 扩展运算符

  • Object.assign(target,source)

  • 数组拷贝 concat()

  • 数组拷贝 slice()

6、JS事件循环?执行机制?

**解释:**单线程非阻塞的脚本语言,单线程是一时间只能做同一件事,非阻塞是代码进行一个异步任务的时候,在这个任务返回结果的时候根据结果去执行相应回调。

**执行机制:**所有任务都在主线程上,形成一个执行栈。主线程外还有一个任务队列。先执行栈中的同步任务,异步任务放到任务队列中。同步任务执行完毕,再依次读取任务队列的异步任务,这时异步任务结束等待状态,进入执行栈开始执行。先执行准备好的微任务,然后再执行宏任务。栈不断获得任务、执行任务、获取任务、再执行的机制。

异步队列又分为:宏任务和微任务,因为宏任务的执行时间较长,所以微任务优于宏任务。

  • 宏任务:setTimeout、setInterval、I/O文件操作、setImmediate中断长时间运行的操作、Ajax 请求、script代码;

  • 微任务:.then、.catch .finally、process.nextTick、async\await;

7、同步异步的区别? 

  • 同步操作**:**是顺序执行的,也就是说,当一个同步任务开始执行时,它必须完成执行后才能继续执行下一个任务。在JavaScript中,大多数的基本操作都是同步的,例如变量赋值、函数调用等。
  • 异步操作**:**则不会阻塞后续代码的执行。当一个异步操作开始时,后续代码会立即执行,而异步操作则在后台继续执行。常见的异步操作包括定时器、网络请求、事件监听等。

为了处理异步操作,JavaScript提供了回调函数、Promise、async/await等机制。这些机制允许我们以同步的方式编写异步代码,使得代码更易于理解和维护。

8、原型?原型链? 

  1. **原型:**原型也是一个对象,通过原型实现对象的属性继承,函数中prototype属性这个对象包含了所有实例共享的属性和方法。prototype属性指向的那个对象叫做原型对象。

  2. **原型的作用:**共享的属性和方法;把不变的方法定义在原型对象上节约内存

  3. **原型链:**当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的_ _ proto _ _隐式原型上查找,即它的构造函数的 prototype,如果还没有找到就会再在构造函数的 prototype 的 __ proto __中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链;

9、数组的api有哪些?

  • reduce :累计器,返回函数累计处理的结果,求和;

  • findIndex :查找元素索引;

  • slice(开始下标,截取个数):截取,左闭右开,不改变;

  • concat:合并两个数组,生成新的数组,不改变;

  • join :数组元素拼接字符串,返回字符串,不改变

  • reverse :反转数组,改变;

  • sort :对原数组单元值排序,(math.random-0.5随机数实现乱序),改变;

  • splice(下标,个数,替换的元素...): 删除一个几个或替换原来数组单元,改变;

  • 遍历数组的方法:

    • every、some、find遍历元素返回符合条件的,返回true/false;

    • filter:遍历筛选符合条件的元素,不改变;

    • forEach:遍历数组没有返回值,查找打印输出值,不改变;

    • map:映射,遍历数组元素,返回处理后的数组,改变,去重;

 10、微信支付调用的哪个api? 

  • wx.requestPayment:用于发起支付请求。
  • wx.onPaymentResultNotify:用于接收支付结果通知。

11、vue2的生命周期? 

  • beforeCreate:初始化
  • created:实例创建完成后被立即调用,data中的数据和方法,未挂载可以访问;
  • beforeMount:挂载开始之前:可以发起服务端请求,请求数据;
  • mounted: 挂载到实例上去之后调用,此时可以操作DOM;(注意:并不能确定子组件被全部挂载,如果需要子组件完全挂载之后执行操作可以使用$nextTick)
  • beforeUpdate:数据更新时调用,发生在虚拟 DOM 打补丁之前;
  • updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁;
  • beforeDestroy:实例销毁之前调用;
  • destroyed:Vue 实例销毁后调用;Vue 实例解绑,事件监听移除,子实例被销毁;

12、vuex的五个属性以及作用? 

**理解:**是一个状态管理中心,核心就是 store(仓库)。Vuex 的状态存储是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

**特点:**集中管理共享的数据,易于开发和后期维护;组件之间数据共享,提高开发效率;响应式的存储数据,能够实时数据与页面的同步

5个核心属性

  • state:公共数据源,放所有共享数据进行存储;

  • getter:类似于Vue的计算属性,对Store中的数据进行加工处理形成新的数据;getter 的返回值会根据它的依赖被缓存起来, 当它的依赖值发生了改变才会被重新计算。

  • mutation:用于修改state中的同步数据;

  • action:处理异步任务,数据commit提交给Mutation间接变更数据;

  • modules:模块化,每个模块有自己单独的state、mutations、actions、getters,方便维护;

13、怎么阻止事件冒泡?

  • event.stopPropagation() :阻止事件继续向上冒泡,但不会阻止事件本身的执行。
  • .stop
  • return false:会阻止事件向上冒泡,还会阻止事件本身的执行。

14、常用事件修饰符?

  • .trim 去除首尾多余的空格
  • .prevent 阻止元素的默认行为(event.preventDefault())
  • .stop 阻止事件冒泡
  • .once 只渲染一次
  • .self 事件只作用在元素本身
  • .number 将值转化为number类型
  • .capter 组件之间捕获
  • .native 事件穿透,让我们可以在自定义组件上定义事件和方法

 15、什么是模板字符串?

模板字符串:`name{name}、{skill}`;    (和插值表达式{{}}记混了)

模板字符串是增强版的字符串,是可以插入表达式的字符串字面量。用反引号(`)标识。 它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

模板字符串中嵌入变量,需要将变量名写在${}之中。

16、 什么是解构赋值?写法? 

解构赋值是一种 JavaScript 表达式,可以将属性/值从对象或数组中取出,赋值给其他变量。它是对赋值运算符的扩展,可以用于数组或对象,并允许对其中的变量进行赋值。作用是简化代码书写,提高代码可读性,同时方便从复杂对象中获取所需的属性值。

  • 数组解构赋值:let [a, b, c] = [1, 2, 3];
  • 对象解构赋值:let {a, b} = {a: 1, b: 2};

17、vue2和vue3的区别?

  1. 双向数据绑定原理:Vue2使用ES5的一个API Object.defineProperty()对数据进行劫持,并结合发布订阅模式的方式来实现双向数据绑定。而Vue3使用了ES6的Proxy API对数据代理,这可以省去for in、闭包等内容来提升效率,并可以监听数组,不用再单独的对数组做特异性操作。
  2. 是否支持碎片:Vue2不支持碎片,而Vue3支持碎片(Fragments),也就是说在组件可以拥有多个根节点。
  3. API类型:Vue2使用选项类型api,选项型api在代码里分割了不同的属性:data,computed,methods等。而Vue3使用了新的合成型API,能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。
  4. 定义数据变量和方法:Vue2是把数据放入data中,在vue2中定义数据变量是data(){},创建的方法要在methods:{}中。而Vue3中的定义方式发生了改变。
  5. 性能:Vue3相比于之前更小巧,组件封装比较好,易用,性能比较好,单页应用用户体验较好。
  6. 命令变化:启动项目命令由npm run dev变成了npm run serve。
  7. 项目结构:移除了配置文件目录,config和build文件;移除了vue.config.js文件;移除了static文件夹新增public文件夹,并且index.html移到public中;在src文件夹中新增了views文件件,用于分类视图组件和公共组件;

 18、商品列表拖拽排序实现思路?(有做过的可以评论一下)

点击事件、拖拽释放事件触发、过渡动画;当用户完成拖放后,你需要更新列表的顺序。 

点击商品,监听拖拽释放,给后端传一个商品id和拖放位置的商品数组下标。后端进行商品列表的查询。返回新的商品列表。

第三家面试记录笔试:

1、var、let、const区别? 

  • 区别:污染全局、块级作用域、重复声明、暂时性死区(先使用后声明中间会出现)

  • var 可以重复声明变量,不受限于块级;有变量提升,可以在声明的上面访问变量,提升到作用域的最顶端,但访问结果是undefined;挂载到全局window;

  • let:声明变量,只能在(块级)作用域内使用,先使用后声明会出现死区,不能重复声明;

  • const 声明常量,用于定义不可修改的值(定义引用数据类型是在堆里面,对象可以修改,数组push的话可以修改),声明之后必须初始化赋值,支持块级作用域;

2、vue-router动态路由?传参方式?

在 Vue Router 中,动态路由允许您根据不同的参数显示不同的内容。动态路由允许您将参数传递给路由,以便在路由之间进行导航时保留状态。要在 Vue Router 中设置动态路由,您需要在路由配置中添加 dynamicSegments 属性。dynamicSegments 属性是一个对象,其中键是动态段名称,值是路径模式。

在Vue Router中,传递动态参数主要有以下几种方式:

  1. 通过路由路径传参:这是最直接的方式,通过在路径中添加参数。例如,/user/:id,其中id就是动态参数。
  2. 通过查询参数传参:可以通过query对象来传递参数,这些参数会被附加在路由路径的末尾,以?开始。例如,/user?id=123
  3. 通过路由元信息(meta)传参:可以在路由配置中添加meta字段来传递元数据,这些数据不直接显示在URL中,但可以在路由组件中访问。
  4. 通过props传参:如果路由配置中设置了props字段为true或对象,那么可以通过props将参数传递给组件。
  5. 通过编程式导航传参:可以使用this.$router.push()方法进行编程式导航,可以传递一个包含参数的对象。

在组件中获取这些参数的方式如下:

  • 通过this.route.params获取动态参数:对于路径中的动态参数,可以通过‘this.route.params`来获取。
  • 通过this.route.query获取查询参数:对于查询参数,可以通过‘this.route.query`来获取。
  • 通过this.route.meta获取元信息:对于元信息,可以通过‘this.route.meta`来获取。
  • 通过this.route.props获取props参数:如果设置了props属性,可以通过‘this.route.props`来获取传递的参数。

3、 v-if 和v-for 可以一起使用吗?

不推荐同时使用

  • 存在一个优先级的问题,同一个节点v-for 比 v-if 优先级高,v-for是要先执行的 ;

  • 性能浪费(遍历的数组很大,要展示的数据很少时),每次渲染的时候都要先进行循环;

  • vue3.0中相反,v-if 总是优先于 v-for 生效。建议避免在同一元素上同时使用两者;

如何同时使用:

  • 可以先使用computed计算属性进行过滤,把不需要的数据过滤掉,剩下的数据再利用v-for循环遍历渲染;

  • 把v-if放到外层

4、 arr = [1,2,4],在4前面插入值3?

let arr = [1, 2, 4];  
arr.splice(2, 0, 3); // 在索引2的位置插入数字3  
console.log(arr); // 输出: [1, 2, 3, 4]

5、 实现跨域的方法?

原理:跨域是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的。 跨域即是通过各种方式,避开浏览器的安全限制。

  • **jsonp:**使用的是jsonp,但存在一些问题,使用get请求不安全,携带数据较小,后来也用过iframe,但只有主域相同才行,也是存在些问题,后来通过了解和学习发现使用代理和proxy代理配合起来使用比较方便,就引导后台按这种方式做下服务器配置,在开发中使用proxy,在服务器上使用nginx代理,这样开发过程中彼此都方便,效率也高;使用步骤:定义一个js文件,通过script标签的src属性;通过定义函数名去接收后台返回调用形式的数据;

  • **CORS:**跨域资源共享 (node和前端项目解决跨域)。原理:是由一系列HTTP响应头组成,响应头决定是否阻止前端js跨域获取资源。同源策略会阻止跨域,但配置CORS相关响应头就可以解决跨域限制。服务器设置Access-Control-Allow-Origin HTTP响应头之后,浏览器将会允许跨域请求

  • **反向代理:**前端地址->本地后端->代理向其他服务器发请求

    (vue.config.js->devServer->配置proxy)  // target要代理的服务器地址;  changeOrigin是否跨域;  pathRewrite路径重写 proxy: {   '/api': {    target: '',      changeOrigin: true,     pathRewrite: {     '^/api': ''   }}}
    
  • window+iframe

  • **proxy代理:**目前常用方式,通过服务器设置代理

    本地向proxy代理服务器发送请求,proxy接收本地请求,转换为目标地址相同IP和端口向目标地址发送请求。proxy: {      "/api": {        // 监听拦截以/api,并替换成target        target: "http://xxx.xxx.xx.xxx:xxxx", // 代理的域名,后端ipconfig查看域名接口地址        changOrigin: true, // 开启代理,允许跨域        pathRewrite: {          "^/api": "", // 重写匹配的字段,如果不需要重写为""        },      },    },
    
  • window.postMessage() :利用h5新特性window.postMessage()

6、vue生命周期? 

7、怎么将字符串转化为数字类型? 

  1. Number()
  2. parseInt() 和 parseFloat()
  3. “+”“-” 操作符

8、computed 和 watch 的区别? 

通俗来讲,既能用 computed 实现又可以用 watch 监听来实现的功能,推荐用 computed。 重点在于 computed 的缓存功能 ,它是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量改变时,计算属性也会跟着改变。watch 监听的是已经在 data 中定义的变量,当该变量变化时,会触发 watch 中的方法。

watch:

  • 监听特定数据的变化(一个数据影响多个数据的变化);

  • 支持异步,限制执行的频率,需要在数据变化时或开销较大的操作时使用;

  • handler:监听到变化时执行的回调函数;

  • deep:true 实现深监听;

  • immediate:true 立即监听;

**compute:**如果给计算属性变量直接赋值,需要使用完整写法(get/set)

场景:一个变量的值,需要用另外变量计算得来。

  • 依赖缓存(一个数据受多个数据影响:购物车商品结算);

  • 依赖的值发生改变重新计算,没有改变就从缓存读取;

  • 返回值当做最新结果,所以不能异步。但是更高效,优先使用;

第四家电话面试记录:

1、es6的新特性?

  • let 、const、Array.of、Array.from、for...of、import 、export、Promise 、

  • set、map、async、await、Object.keys、Object.assign

  • 新增声明命令 let 和 const;模板字符串;数组和对象的解构赋值;...展开运算符;

  • 函数的扩展:函数的默认参数;箭头函数;

  • 对象的扩展:属性的简写;Object.keys()返回一个由属性名组成的数组;Object.assign ():合并对象,拷贝合并一个多个对象到目标对象。可以接收多个参数;

  • 数组的扩展:Array.of()将一组值,转换为数组。Array.from()将两类对象转为真正的数组

  • for...of 循环;

  • import 和 export;

  • Promise 对象;async、await编写形似同步的代码来处理异步流程;

  • set 数据结构:类似于数组,但是Set数据中的元素都是唯一的,没有重复值;

  • map 数据结构:映射,根据一个数组生成一个新的数组,实现对象键名与键值一 一对应的关系;

2、v-show和v-if的区别?

都可以用来控制元素的显示和隐藏;区别:

  • 控制方式:v-if是条件渲染指令,它会根据表达式的真假条件来渲染或销毁元素。这意味着当条件为假时,元素将从DOM中完全移除。而v-show是通过修改CSS的display属性来控制元素的显示和隐藏,当指令值为false时,元素的display属性被设置为none,但元素仍然存在于DOM中。
  • 性能开销:v-if有更高的初始渲染开销,因为它涉及到DOM的增删操作,而v-show只是修改CSS属性,相对来说操作更简单。另外,由于v-if会进行条件的真假判断,因此它的性能开销在频繁切换时相对较小。相比之下,由于v-show只是简单地切换CSS属性,因此在频繁切换时性能开销较小。
  • 适用场景:v-if适合用于条件不经常改变的场景,因为它在条件为假时能完全移除元素,有助于提高性能。而v-show更适合用于频繁切换显示和隐藏的场景,因为它能快速切换元素的显示状态而不需要进行DOM操作。
  • 兼容性:在旧版本的浏览器中,使用v-show可能会有兼容性问题,因此在使用时需要注意兼容性问题。

3、浏览器渲染html页面的过程?

  • 解析 HTML,构成 DOM 树
  • 解析加载的样式,构建样式规则树
  • 加载 JavaScript,执行 JavaScript 代码
  • DOM 树和样式规则树进行匹配,构成渲染树
  • 计算元素位置进行页面布局 绘制页面
  • 最终在浏览器中呈现

4、组件之间的传值?

  • 父传子props:子组件props接收 -> 父组件使用v-bind属性给props传值;(单项数据流)

    父级: :list = 'list' 子级: props:{ list:{ type:String } }

  • 子传父emit: 子级$emit触发父的事件并可以携带参数 -> 父组件监听使用@自定义事件名=父的方法;( parent、children Ref获取实例的方式调用组件的属性或者方法)

    父级:@test = 'newTest' //@自定义事件名="事件处理函数" 子级:emit("test,test.value)//this.emit("test',test.value) //this.emit("自定义事件名", 传值)

  • 非父子组件:eventBus事件总线实现跨组件通信,组件template中绑定事件

    Vue.prototype.bus=newVue()自定义事件eventBus.bus = new Vue() 自定义事件 eventBus.emit('事件名',值) eventBus.$on('事件名',函数体)

5、vue生命周期?

6、data的值怎么定义?

  • 对象字面量定义

    data() { return { message: 'Hello Vue!' }; }

**

  • 对象简写

**

data: {    message: 'Hello Vue!'  }

**

  • 函数返回对象

**

data() {    return {      message: 'Hello Vue!'    };  }

7、cookie持久化?

  1. 设置过期时间:通过设置 Cookie 的过期时间,可以让它在指定的时间后失效。如果用户在浏览器中关闭或清空了浏览器缓存,Cookie 仍然可以在过期时间之前被重新加载到浏览器中。例如,可以使用 Expires 属性来设置 Cookie 的过期时间。
  2. 使用 HttpOnly 属性:HttpOnly 属性可以防止 JavaScript 代码访问 Cookie。这意味着即使攻击者能够获取到用户的 Cookie,他们也无法使用 JavaScript 代码来读取或修改它。这可以增加 Cookie 的安全性。
  3. 使用 Secure 属性:Secure 属性可以确保 Cookie 只能通过 HTTPS 协议传输,而不是通过 HTTP 协议传输。这可以防止 Cookie 在传输过程中被截获或篡改。
  4. 使用加密技术:为了确保 Cookie 的安全性,可以使用加密技术对 Cookie 进行加密。这样即使攻击者能够获取到用户的 Cookie,他们也无法读取或修改其中的内容。
  5. 使用数据库存储:如果需要更高级别的持久化,可以将数据存储在数据库中,而不是使用 Cookie。这样即使浏览器关闭或清空了缓存,数据仍然可以被重新加载。