听阳光的猫

道阻且长、望你如一

0%

2021面试记录

4.5 盛扬信远

axios配置

它是基于promise的http库

传值的方法深浅拷贝

区别:浅拷贝只是增加了一个指针指向已存在的内存地址,仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。深拷贝是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。

浅拷贝:

(1)for···in只循环第一层

(2)Object.assign方法

(3)直接用=赋值

深拷贝:

(1)采用递归去拷贝所有层级属性

(2) 通过JSON对象来实现深拷贝

(3)通过jQuery的extend方法实现深拷贝

(4)lodash函数库实现深拷贝

(5)Reflect法

(6)如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象

(7)用slice实现对数组的深拷贝

(8)用concat实现对数组的深拷贝

(9)直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

(10)使用扩展运算符实现深拷贝

计算属性惰性求值

$set

$nextTick

类数组如何变成数组

vue传参的方式

1.Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,
并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,
提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

优缺点

  • 优点
    • 解决了多层组件之间繁琐的事件传播。
    • 解决了多组件依赖统同一状态的问题。
    • 单向数据流
    • 为Vue量身定做,学习成本不高
  • 缺点
    • 不能做数据持久化,刷新页面就要重制,要做数据持久化可以考虑使用localstorage。
    • 增加额外的代码体积,简单的业务场景不建议使用。

2.EventBus 通过共享一个vue实例,使用该实例的$on以及$emit实现数据传递。

使用方法

下面是简单的使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// bus.js
import Vue from 'vue'
export default new Vue({})

// component-a.js
import bus from './bus.js'
export default {
created () {
bus.$on('event-name', (preload) => {
// ...
})
}
}

// component-b.js
import bus from './bus.js'
export default {
created () {
bus.$emit('event-name', preload)
}
}

优缺点

  • 优点
    • 解决了多层组件之间繁琐的事件传播。
    • 使用原理十分简单,代码量少。
  • 缺点
    • 由于是都使用一个Vue实例,所以容易出现重复触发的情景,例如:
      1. 多人开发时,A、B两个人定义了同一个事件名。
      2. 两个页面都定义了同一个事件名,并且没有用$off销毁(常出现在路由切换时)。
      3. 在for出来的组件里注册。
    • 项目一大用这种方式管理事件会十分混乱,这时候建议用vuex。

3.props和$emit/$on

最基本的父组件给子组件传递数据方式,将我们自定义的属性传给子组件,子组件通过$emit方法,触发父组件v-on的事件,从而实现子组件触发父组件方法

优缺点

  • 优点
    • 使用最为简单,也是父子组件传递最常见的方法。
    • Vue为给props提供了类型检查支持。
    • $emit不会修改到别的组件的同名事件,因为他只能触发父级的事件,这里和event-bus不同
  • 缺点
    • 单一组件层级一深需要逐层传递,会有很多不必要的代码量。
    • 不能解决了多组件依赖统同一状态的问题。

$attrs/$listeners可以将父组件的props和事件监听器继承给子元素,在子组件可以调用到父组件的事件和props

4.provide/inject

在父组件上通过provide提供给后代组件的数据/方法,在后代组件上通过inject来接收被注入的数据/方法。

优缺点

  • 优点
    • 不用像props一层层传递,可以跨层级传递。
  • 缺点
    • 用这种方式传递的属性是非响应式的,所以尽可能来传递一些静态属性。
    • 引用官网的话是它将你的应用以目前的组件组织方式耦合了起来,使重构变得更加困难。,我对这句话的理解是用了provide/inject你就要遵循它的组件组织方式,在项目的重构时如果要破坏这个组织方式会有额外的开发成本,其实event-bus也有这个问题。

5.slot

你可以在组件的html模版里添加自定义内容,这个内容可以是任何代码模版,就像:

1
2
3
4
5
<navigation-link url="/profile">
<!-- 添加一个 Font Awesome 图标 -->
<span class="fa fa-user"></span>
Your Profile
</navigation-link>

父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

你也可以通过slot-scope属性来实现从子组件将一些信息传递给父组件,注意这个属性是vue2.1.0+新增的。

优缺点

  • 优点
    • 可以在父组件里自定义插入到子组件里的内容,虽然其他属性也可以,但是我觉得slot更倾向于自定义的条件是来自于父容器中。
    • 复用性好,适合做组件开发。
  • 缺点
    • 和props一样不支持跨层级传递。

6.$parent/$children

通过$parent/$children可以拿到父子组件的实例,从而调用实例里的方法,实现父子组件通信。

优缺点

  • 优点
    • 可以拿到父子组件实例,从而拥有实例里的所有属性。
  • 缺点
    • 用这种方法写出来的组件十分难维护,因为你并不知道数据的来源是哪里,有悖于单向数据流的原则
    • this.$children拿到的是一个数组,你并不能很准确的找到你要找的子组件的位置,尤其是子组件多的时候。

push

let、var

cherry-pick

vue写H5和安卓联调

js基础

实际过程中快速解决问题

uni-app

cookie和session的区别

在这里插入图片描述

本地储存localStorage与cookie的区别
1)cookie在浏览器与服务器之间来回传递
sessionStorage和localStorage不会把数据发给服务器,仅在本地保存
2)数据有效期不同
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
sessionStorage:仅在当前浏览器窗口关闭前有效
localStorage 始终有效,长期保存
3)cookie数据还有路径的概念,可以限制cookie只属于某个路径下
存储大小也不同,cookie数据不能超过4k,sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
4)作用域不用
sessionStorage不在不同的浏览器窗口中共享
localStorage在所有同源窗口中都是共享的
cookie也是在所有同源窗口中都是共享的
WebStorage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便

cookie、session和localStorage的区别
1)cookie的内容主要包括:名字、值、过期时间、路径和域,路径与域一起构成cookie的作用范围。若不设置时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就会消失,这种生命期为浏览器会话期的cookie被称为会话cookie
2)会话cookie一般不存储在硬盘而是保存在内存里,当然这个行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再打开浏览器这些cookie仍然有效直到超过设定的过期时间。对于保存在内存里的cookie,不同的浏览器有不同的处理方式session机制。
3)当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识(称为session id),如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。

cookie和session的区别
1)cookie数据存放在客户的浏览器上,session数据放在服务器上
2)cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session
3)session会在一定时间内保存在服务器上,当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
4)单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
5)建议将登录信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中
6)session保存在服务器,客户端不知道其中的信心;cookie保存在客户端,服务器能够知道其中的信息
7)session中保存的是对象,cookie中保存的是字符串
8)session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到,而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的

web Storage和cookie的区别
1)Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的,cookie的大小是受限的,并且每次请求一个新的页面的时候cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可跨域调用
2)web storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie
3)但是cookie也是不可或缺的,cookie的作用是与服务器进行交互,作为http规范的一部分而存在的,而web Storage仅仅是为了在本地“存储”数据而生
sessionStorage、localStorage、cookie都是在浏览器端存储的数据,其中sessionStorage的概念很特别,引入了一个“浏览器窗口”的概念,sessionStorage是在同源的同窗口中,始终存在的数据,也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一个页面,数据仍然存在,关闭窗口后,sessionStorage就会被销毁,同时“独立”打开的不同窗口,即使是同一页面,sessionStorage对象也是不同的
4)Web Storage的好处
减少网络流量:一旦数据保存在本地之后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要的来回传递
快速显示数据:性能好,从本地读数据比通过网络从服务器上获得数据快得多,本地数据可以及时获得,再加上网页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示
临时存储:很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便

浏览器本地存储与服务器端存储的区别
1)数据既可以在浏览器本地存储,也可以在服务器端存储
2)浏览器可以保存一些数据,需要的时候直接从本地存取,sessionStorage、localStorage和cookie都是由浏览器存储在本地的数据
3)服务器端也可以保存所有用户的所有数据,但需要的时候浏览器要向服务器请求数据
4)服务器端可以保存用户的持久数据,如数据库和云存储将用户的大量数据保存在服务器端 ,服务器端也可以保存用户的临时会话数据,服务器端的session机制,如jsp的session对象,数据保存在服务器上
5)服务器和浏览器之间仅需传递session id即可,服务器根据session id找到对应用户的session对象,会话数据仅在一段时间内有效,这个时间就是server端设置的session有效期
6)服务器端保存所有的用户的数据,所以服务器端的开销较大,而浏览器端保存则把不同用户需要的数据分别保存在用户各自的浏览器中,浏览器端一般只用来存储小数据,而非服务可以存储大数据或小数据服务器存储数据安全一些,浏览器只适合存储一般数据

sessionStorage、localStorage和cookie的区别
1)相同点是都是保存在浏览器端、且同源的
2)cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下
3)存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
4)数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
5)作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的
6)web Storage支持事件通知机制,可以将数据更新的通知发送给监听者
7)web Storage的api接口使用更方便

sessionStorage与页面js数据对象的区别
1)页面中一般的js对象的生存期仅在当前页面有效,因此刷新页面或转到另一页面这样的重新加载页面的情况,数据就不存在了
2)sessionStorage只要同源的同窗口中,刷新页面或进入同源的不同页面,数据始终存在,也就是说只要浏览器不关闭,数据仍然存在

4.9 华为外包

盒模型

CSS盒模型box-sizing:content-box

属性width,height只包含内容content,不包含border和padding。

IE盒模型box-sizing:border-box

属性width,height包含border和padding,指的是content+padding+border。

清除浮动

给浮动元素的容器添加overflow:hidden;overflow:auto;可以清除浮动

使用CSS的:after伪元素

1
2
3
4
5
6
7
.clearfix:after{
content: "020";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

vue的传参方式

vuex

4.9澳润激

4.12朋悦科技

箭头函数和普通函数的区别

一.外形不同:箭头函数使用箭头定义,普通函数中没有

二.箭头函数都是匿名函数

普通函数可以有匿名函数,也可以有具体名函数,但是箭头函数都是匿名函数。

三.箭头函数不能用于构造函数,不能使用new

普通函数可以用于构造函数,以此创建对象实例。

四.箭头函数中this的指向不同

在普通函数中,this总是指向调用它的对象,如果用作构造函数,this指向创建的对象实例。

1.箭头函数本身不创建this

也可以说箭头函数本身没有this,但是它在声明时可以捕获其所在上下文的this供自己使用。

注意:this一旦被捕获,就不再发生变化

2.结合call(),apply()方法使用

箭头函数结合call(),apply()方法调用一个函数时,只传入一个参数对this没有影响。

3.箭头函数不绑定arguments,取而代之用rest参数…解决

每一个普通函数调用后都具有一个arguments对象,用来存储实际传递的参数。但是箭头函数并没有此对象。

4.其他区别

(1)箭头函数不能Generator函数,不能使用yeild关键字。

(2)箭头函数不具有prototype原型对象。

(3)箭头函数不具有super。

(4)箭头函数不具有new.target。

2、var、let、const之间的区别

  var声明变量可以重复声明,而let不可以重复声明

  var是不受限于块级的,而let是受限于块级

  var会与window相映射(会挂一个属性),而let不与window相映射

  var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错

  const声明之后必须赋值,否则会报错

  const定义不可变的量,改变了就会报错

  const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错

3、使用箭头函数应注意什么?

  (1)用了箭头函数,this就不是指向window,而是父级(指向是可变的)

  (2)不能够使用arguments对象

  (3)不能用作构造函数,这就是说不能够使用new命令,否则会抛出一个错误

  (4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数

4.13朗新科技

vue 响应式的基本原理

1.通过Object.defineProperty来实现监听数据的改变和读取(属性中的getter和setter方法) 实现数据劫持

2.观察者模式(发布者-订阅者)

观察者(订阅者) – Watcher:

update():当事件发生时,具体要做的事情

目标(发布者) – Dep:

①subs 数组:存储所有的观察者

②addSub():添加观察者

③notify():当事件发生,调用所有观察者的 update() 方法

3.当数据发生改变通过发布者订阅者模式来进行通知 进行界面刷新

4.14最初文化 线下15:00

​ 项目开发的流程是什么?

​ 需求确认——概要设计——详细设计——编码——单元测试——集成测试——系统测试——维护

4.15 趣块科技10:30

vue的源码

ajax的请求原理

js的源码

css预处理器

less如何自定义一个函数

node了解什么

算法有了解吗

spa解决seo有两个方案,ssr 和 prerender。

4.15 拓维云创 14:00

介绍一下flex布局

image-20200915180112899

vue组件的scoped

父组件如何修改有scoped的子组件

如果想对设置了scoped的子组件里的元素进行控制可以使用’>>>’或者’deep’

一些预处理程序例如sass不能解析>>>属性,这种情况下可以用deep,它是>>>的别名,工作原理相同。

less、scss对比css有什么优点

  1. 支持嵌套
  2. 支持变量定义
  3. 支持“模板函数”

深拷贝和浅拷贝有什么优缺点

es6里面的promise

简单介绍一下watch和computed

computed和watch的区别

计算属性computed:

  • 支持缓存,只有依赖数据发生改变,才会重新进行计算
  • 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
  • computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
  • 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

侦听属性watch:

  • 不支持缓存,数据变,直接会触发相应的操作;
  • watch支持异步;
  • 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
  • 当一个属性发生变化时,需要执行对应的操作;一对多;
  • 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数:immediate:组件加载立即触发回调函数执行;deep:true;//显示的进行深度监听

computed里面的a可以直接this.a赋值吗

watch监听里面有哪些配置项

组件通信方式

vuex里面的module

module里面的数据可以互相调用吗

actions里各个方法的第一个参数其实有很多属性,只是我们平时习惯了解构的写法,如setMenuData({commit, state},data)。当把第一个参数的值全输出,如setMenuData(param,data),输出param

$nextTick是什么?

vue实现响应式并不是数据发生变化后dom立即变化,而是按照一定的策略来进行dom更新。

nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用nextTick,则可以在回调中获取更新后的 DOM

4.15 佰钧成 16:00

foreach和map的区别

  • 都是循环遍历数组中的每一项
  • forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是item(当前每一项)、index(索引值)、arr(原数组)
  • 匿名函数中的this都是指向window
  • 只能遍历数组

1.forEach()

没有返回值。

2.map()

有返回值,可以return 出来。

for in 和for of

总结:for…in 循环主要是为了遍历对象而生,不适用于遍历数组

for…of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象

promise.all和promise.any

  • Promise.race

类方法,多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败。 。

  • Promise.all

类方法,多个 Promise 任务同时执行。

如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。

冒泡排序

冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢”浮”到数列的顶端。

传参方式

深拷贝和浅拷贝的区别

vue封装组件的过程

使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。

防抖和节流

函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

组件化和模块化

组件:把重复的代码提取出来合并成为一个个组件,组件最重要的就是重用(复用)

模块:分属同一功能/业务的代码进行隔离(分装)成独立的模块,可以独立运行,独立管理,每个模块有很多接口,可供调用

组件化模块化优点:开发调试效率高、可维护性强、避免阻断、版本管理更容易

开发用哪些软件

图表

4.15 天用维勤17:00

垂直居中

一、行高(line-height)法

如果要垂直居中的只有一行或几个文字,那它的制作最为简单,只要让文字的行高和容器的高度相同即可,比如:

1
2
3
4
5
6
p { 
height:30px;
line-height:30px;
width:100px;
overflow:hidden;
}

二、内边距(padding)法

另一种方法和行高法很相似,它同样适合一行或几行文字垂直居中,原理就是利用padding将内容垂直居中,比如:

1
2
3
p { 
padding:20px 0;
}

三、模拟表格法

将容器设置为display:table,然后将子元素也就是要垂直居中显示的元素设置为display:table-cell,然后加上vertical-align:middle来实现。

html结构如下:

1
2
3
4
5
6
<div id="wrapper">
<div id="cell">
<p>测试垂直居中效果测试垂直居中效果</p>
<p>测试垂直居中效果测试垂直居中效果</p>
</div>
</div>

css代码:

1
2
#wrapper {display:table;width:300px;height:300px;background:#000;margin:0 auto;color:red;}
#cell{display:table-cell; vertical-align:middle;}

四、CSS3的transform来实现

css代码如下:

1
2
3
4
5
6
7
8
9
.center-vertical{
position: relative;
top:50%;
transform:translateY(-50%);
}.center-horizontal{
position: relative;
left:50%;
transform:translateX(-50%);
}

五:css3的box方法实现水平垂直居中

html代码:

1
2
3
4
5
6
7
<div class="center">
<div class="text">
<p>我是多行文字</p>
<p>我是多行文字</p>
<p>我是多行文字</p>
</div>
</div>

css代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
.center {
width: 300px;
height: 200px;
padding: 10px;
border: 1px solid #ccc;
background:#000;
color:#fff;
margin: 20px auto;
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;

display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: center;
-moz-box-align: center;

display: -o-box;
-o-box-orient: horizontal;
-o-box-pack: center;
-o-box-align: center;

display: -ms-box;
-ms-box-orient: horizontal;
-ms-box-pack: center;
-ms-box-align: center;

display: box;
box-orient: horizontal;
box-pack: center;
box-align: center;
}

六:flex布局

html代码:

1
2
3
4
5
6
<div class="flex">
<div>
<p>我是多行文字我是多行文字我是多行文字我是多行文字</p>
<p>我是多行文字我是多行文字我是多行文字我是多行文字</p>
</div>
</div>

CSS代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.flex{
/*flex 布局*/
display: flex;
/*实现垂直居中*/
align-items: center;
/*实现水平居中*/
justify-content: center;

text-align: justify;
width:200px;
height:200px;
background: #000;
margin:0 auto;
color:#fff;
}

盒模型

谷歌font-size最新

js的数据类型、区别

js基本数据类型:

js基本数据类型包括:undefined,null,number,boolean,string.基本数据类型是按值访问的,就是说我们可以操作保存在变量中的实际的值

  1. 基本数据类型的值是不可变的
  2. 基本数据类型不可以添加属性和方法
  3. 基本数据类型的赋值是简单赋值
  4. 基本数据类型的比较是值的比较
  5. 基本数据类型是存放在栈区的

js引用类型:

js中除了上面的基本类型之外就是引用类型了,也可以说就是对象了,比如:Object,Array,Function,Data等

  1. 引用类型的值是可以改变的
  2. 引用类型可以添加属性和方法
  3. 引用类型的赋值是对象引用
  4. 引用类型的比较是引用的比较
  5. 引用类型是同时保存在栈区和堆区中的

登陆的过程

img

导航守卫

全局路由钩子:beforeEach(to,from, next)、beforeResolve(to,from, next)、afterEach(to,from);

独享路由钩子:beforeEnter(to,from, next);

组件内路由钩子:beforeRouteEnter(to,from, next)、beforeRouteUpdate(to,from, next)、beforeRouteLeave(to,from, next)

vue生命周期

响应式原理

Vue的双向数据绑定原理是什么?

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:

1、需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

2、compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

3、Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

4、MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

深拷贝、浅拷贝

介绍一下vue轮子

vue3.0的改变

vuex刷新项目的时候数据如何变化

一般在登录成功的时候需要把用户信息,菜单信息放置vuex中,作为全局的共享数据。 但是在页面刷新的时候vuex. 因为vuex里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,vuex里面的数据就会被重新赋值。

从vuex中获取的数据能直接更改吗?

从vuex中取的数据,不能直接更改,需要浅拷贝对象之后更改,否则报错;

vuex中的数据在页面刷新后数据消失

用sessionstorage 或者 localstorage 存储数据

vuex的缺点

Vuex优势:相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到。

Vuex劣势:在刷新页面后,vuex会重新更新state,所以,存储的数据会丢失。

router和route的区别

route为当前router跳转对象里面可以获取name、path、query、params等

router为VueRouter实例,想要导航到不同URL,则使用router.push方法

对promise的理解

去重函数

4.16兆百特 9:30

flex的其他属性

http状态码403

1xx:1开头的是信息状态码
2xx:2开头的是请求成功
3xx:3开头的是重定向
4xx:4开头的是客户端错误
5xx:5开头的是服务器错误

image-20200915175517061

class~

这个~符号可以定位那些某属性值是空格分隔多值的标签。

数组的方法有哪些

  1. Array.from() 方法从一个类似数组或可迭代对象中创建一个新的,浅拷贝的数组实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]

console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]

let s = new Set(['foo', window]);
Array.from(s);
// ["foo", window]

function f() {
return Array.from(arguments);
}
f(1, 2, 3);
// [1, 2, 3]

function combine(){
let arr = [].concat.apply([], arguments); //没有去重复的新数组
return Array.from(new Set(arr));
}
var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n)); // [1, 2, 3]

2.Array.isArray() 用于确定传递的值是否是一个Array。

1
2
3
4
5
6
7
8
Array.isArray([1, 2, 3]);  
// true
Array.isArray({foo: 123});
// false
Array.isArray("foobar");
// false
Array.isArray(undefined);
// false

3.Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。

Array.of() 和 Array 构造函数之间的区别在于处理整数参数:Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。

1
2
3
4
Array.of(7);       // [7] 
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
  1. concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
1
2
3
4
var array1 = ['a', 'b', 'c'];
var array2 = ['d', 'e', 'f'];
console.log(array1.concat(array2));
// expected output: Array ["a", "b", "c", "d", "e", "f"]

5.copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。

1
2
3
4
5
6
7
8
9
var array1 = ['a', 'b', 'c', 'd', 'e'];
// copy to index 0 the element at index 3

console.log(array1.copyWithin(0, 3, 4));
// expected output: Array ["d", "b", "c", "d", "e"]

// copy to index 1 all elements from index 3 to the end
console.log(array1.copyWithin(1, 3));
// expected output: Array ["d", "d", "e", "d", "e"]

6.entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。

1
2
3
4
5
6
7
8
9
var array1 = ['a', 'b', 'c'];

var iterator1 = array1.entries();

console.log(iterator1.next().value);
// expected output: Array [0, "a"]

console.log(iterator1.next().value);
// expected output: Array [1, "b"]

7.every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

1
2
3
4
5
6
7
8
function isBelowThreshold(currentValue) {
return currentValue < 40;
}

var array1 = [1, 30, 39, 29, 10, 13];

console.log(array1.every(isBelowThreshold));
// expected output: true
  1. fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
1
2
3
4
5
6
7
8
9
10
11
12
var array1 = [1, 2, 3, 4];

// fill with 0 from position 2 until position 4
console.log(array1.fill(0, 2, 4));
// expected output: [1, 2, 0, 0]

// fill with 5 from position 1
console.log(array1.fill(5, 1));
// expected output: [1, 5, 5, 5]

console.log(array1.fill(6));
// expected output: [6, 6, 6, 6]
  1. filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
1
2
3
4
5
function isBigEnough(element) {
return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
  1. find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
1
2
3
4
5
6
7
8
var array1 = [5, 12, 8, 130, 44];

var found = array1.find(function(element) {
return element > 10;
});

console.log(found);
// expected output: 12

11.findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

1
2
3
4
5
6
7
8
var array1 = [5, 12, 8, 130, 44];

function isLargeNumber(element) {
return element > 13;
}

console.log(array1.findIndex(isLargeNumber));
// expected output: 3
  1. flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回 ,flat() 方法会移除数组中的空项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
  1. flatMap()方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map和 深度值1的 flat几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。
1
2
3
4
5
6
7
let arr = ["今天天气不错", "", "早上好"]

arr.map(s => s.split(""))
// [["今", "天", "天", "气", "不", "错"],[],["早", "上", "好"]]

arr.flatMap(s => s.split(''));
// ["今", "天", "天", "气", "不", "错", "早", "上", "好"]

14.forEach() 方法对数组的每个元素执行一次提供的函数。

1
2
3
4
5
6
7
8
9
10
11
12
const items = ['item1', 'item2', 'item3'];
const copy = [];

// before
for (let i=0; i<items.length; i++) {
copy.push(items[i]);
}

// after
items.forEach(function(item){
copy.push(item);
});
  1. includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
1
2
3
4
5
6
7
8
9
10
11
12
var array1 = [1, 2, 3];

console.log(array1.includes(2));
// expected output: true

var pets = ['cat', 'dog', 'bat'];

console.log(pets.includes('cat'));
// expected output: true

console.log(pets.includes('at'));
// expected output: false
  1. indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
1
2
3
4
5
6
7
8
9
10
11
var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];

console.log(beasts.indexOf('bison'));
// expected output: 1

// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4

console.log(beasts.indexOf('giraffe'));
// expected output: -1
  1. join()方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。
1
2
3
4
5
6
7
8
9
10
var elements = ['Fire', 'Air', 'Water'];

console.log(elements.join());
// expected output: "Fire,Air,Water"

console.log(elements.join(''));
// expected output: "FireAirWater"

console.log(elements.join('-'));
// expected output: "Fire-Air-Water"
  1. keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。
1
2
3
4
5
6
var array1 = ['a', 'b', 'c'];
var iterator = array1.keys();

for (let key of iterator) {
console.log(key); // expected output: 0 1 2
}
  1. lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。
1
2
3
4
5
6
7
var animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];

console.log(animals.lastIndexOf('Dodo'));
// expected output: 3

console.log(animals.lastIndexOf('Tiger'));
// expected output: 1

20.map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

1
2
3
4
5
6
7
var array1 = [1, 4, 9, 16];

// pass a function to map
const map1 = array1.map(x => x * 2);

console.log(map1);
// expected output: Array [2, 8, 18, 32]
  1. pop()方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
1
2
3
4
5
6
7
8
9
10
11
12
var plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];

console.log(plants.pop());
// expected output: "tomato"

console.log(plants);
// expected output: Array ["broccoli", "cauliflower", "cabbage", "kale"]

plants.pop();

console.log(plants);
// expected output: Array ["broccoli", "cauliflower", "cabbage"]
  1. push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
1
2
3
4
5
6
7
8
9
10
11
12
var animals = ['pigs', 'goats', 'sheep'];

console.log(animals.push('cows'));
// expected output: 4

console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows"]

animals.push('chickens');

console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows", "chickens"]
  1. reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
1
2
3
4
5
6
7
8
9
10
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
  1. reduceRight() 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
1
2
3
4
5
6
const array1 = [[0, 1], [2, 3], [4, 5]].reduceRight(
(accumulator, currentValue) => accumulator.concat(currentValue)
);

console.log(array1);
// expected output: Array [4, 5, 2, 3, 0, 1]
  1. reverse() 方法将数组中元素的位置颠倒,并返回该数组。该方法会改变原数组。
1
2
3
4
5
6
7
8
9
10
11
12
var array1 = ['one', 'two', 'three'];
console.log('array1: ', array1);
// expected output: Array ['one', 'two', 'three']

var reversed = array1.reverse();
console.log('reversed: ', reversed);
// expected output: Array ['three', 'two', 'one']

/* Careful: reverse is destructive. It also changes
the original array */
console.log('array1: ', array1);
// expected output: Array ['three', 'two', 'one']
  1. shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
1
2
3
4
5
6
7
8
9
var array1 = [1, 2, 3];

var firstElement = array1.shift();

console.log(array1);
// expected output: Array [2, 3]

console.log(firstElement);
// expected output: 1

27.slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

1
2
3
4
5
6
7
8
9
10
var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// expected output: Array ["bison", "camel", "duck", "elephant"]
  1. some() 方法测试是否至少有一个元素可以通过被提供的函数方法。该方法返回一个Boolean类型的值。
1
2
3
4
5
6
7
8
9
ar array = [1, 2, 3, 4, 5];

var even = function(element) {
// checks whether an element is even
return element % 2 === 0;
};

console.log(array.some(even));
// expected output: true

29.sort()方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的

由于它取决于具体实现,因此无法保证排序的时间和空间复杂性

1
2
3
4
5
6
7
8
9
10
11
12
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
return a - b;
});
console.log(numbers);

也可以写成:
var numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);

// [1, 2, 3, 4, 5]
  1. splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
1
2
3
4
5
6
7
8
9
10
var months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'June']

months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'May']
  1. toLocaleString() 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开。
1
2
3
4
5
6
var array1 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
var localeString = array1.toLocaleString('en', {timeZone: "UTC"});

console.log(localeString);
// expected output: "1,a,12/21/1997, 2:12:00 PM",
// This assumes "en" locale and UTC timezone - your results may vary
  1. toString() 返回一个字符串,表示指定的数组及其元素。
1
2
3
4
var array1 = [1, 2, 'a', '1a'];

console.log(array1.toString());
// expected output: "1,2,a,1a"

33.unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。

1
2
3
4
5
6
7
var array1 = [1, 2, 3];

console.log(array1.unshift(4, 5));
// expected output: 5

console.log(array1);
// expected output: Array [4, 5, 1, 2, 3]
  1. values() 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值.
1
2
3
4
5
6
const array1 = ['a', 'b', 'c'];
const iterator = array1.values();

for (const value of iterator) {
console.log(value); // expected output: "a" "b" "c"
}

splice有几个参数

使用css隐藏元素

  1. visibility: hidden,设置元素隐藏
  2. opacity: 0,设置元素隐藏
  3. display:none,设置元素隐藏
  4. position: absolute,设置元素隐藏

let、var和const的区别

如何配置vue.config

pc:jquery python+ django

UI:react

4.16 Udesk沃丰科技14:00

虚拟dom

虚拟DOM就是为了解决浏览器性能问题而被设计出来的。如前,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

一、什么是虚拟DOM
虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象 状态变更时,记录新树和旧树的差异
最后把差异更新到真正的dom中.
虚拟DOM的作用:使用原生js或者jquery写页面的时候会发现操作DOM是一件非常麻烦的一件事情,往往是DOM标签
和js逻辑同时写在js文件里,数据交互时不时还要写很多的input隐藏域,如果没有好的代码规范的话会显得代码非常冗
余混乱,耦合性高并且难以维护。
另外一方面在浏览器里一遍又一遍的渲染DOM是非常非常消耗性能的,常常会出现页面卡死的情况;所以尽量减少对
DOM的操作成为了优化前端性能的必要手段,vdom就是将DOM的对比放在了js层,通过对比不同之处来选择新渲染
DOM节点,从而提高渲染效率。
二、patch函数
patch函数的执行分为两个阶段,两次传递的参数都是两个

第一阶段为虚拟dom的第一次渲染,传递的两个参数分别是放真实DOM的container和生成的vnode,此时patch函数的作用是用来将初次生成的真实DOM结构挂载到指定的container上面。

第二阶段传递的两个参数分别为vnode和newVnode,此时patch函数的作用是使用diff算法对比两个参数的差异,进而更新参数变化的DOM节点;

可以发发现h函数和patch函数在cnabbdom中实现vdom到真实DOM的转化起到了至关重要的作用,那么还有一个很重要的环节,patch函数中是怎么样实现对比两个vnode从而实现对真实DOM的更新的呢,这里还要提一下snabbdom的另外一个核心算法,即diff算法。

三、diff算法
其实在我们日常开发中我们都在接触类似与diff算法的一些软件,比如svn可以看到当前代码和svn服务器上代码的不同之处,再如Beyond Compare这款软件也可以为我们指出两个对比文件的不同之处

虚拟DOM的优缺点:

优点:
保证性能下限: 虚拟DOM可以经过diff找出最小差异,然后批量进行patch,这种操作虽然比不上手动优化,但是比起粗暴的DOM操作性能要好很多,因此虚拟DOM可以保证性能下限
无需手动操作DOM: 虚拟DOM的diff和patch都是在一次更新中自动进行的,我们无需手动操作DOM,极大提高开发效率
跨平台: 虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、移动端开发等等
缺点:
无法进行极致优化: 在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化,比如VScode采用直接手动操作DOM的方式进行极端的性能优化

keep-alive

在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。

也就是说,keepalive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的*组件缓存

keep-alive是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM

重绘和回流

在讨论回流与重绘之前,我们要知道:

  1. 浏览器使用流式布局模型 (Flow Based Layout)。
  2. 浏览器会把HTML解析成DOM,把CSS解析成CSSOMDOMCSSOM合并就产生了Render Tree
  3. 有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。
  4. 由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。

一句话:回流必将引起重绘,重绘不一定会引起回流。

回流 (Reflow)

Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

会导致回流的操作:

  • 页面首次渲染
  • 浏览器窗口大小发生改变
  • 元素尺寸或位置发生改变
  • 元素内容变化(文字数量或图片大小等等)
  • 元素字体大小变化
  • 添加或者删除可见DOM元素
  • 激活CSS伪类(例如::hover
  • 查询某些属性或调用某些方法

一些常用且会导致回流的属性和方法:

  • clientWidthclientHeightclientTopclientLeft
  • offsetWidthoffsetHeightoffsetTopoffsetLeft
  • scrollWidthscrollHeightscrollTopscrollLeft
  • scrollIntoView()scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

重绘 (Repaint)

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:colorbackground-colorvisibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

性能影响

回流比重绘的代价要更高。

有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。

现代浏览器会对频繁的回流或重绘操作进行优化:

浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。

当你访问以下属性或方法时,浏览器会立刻清空队列:

  • clientWidthclientHeightclientTopclientLeft
  • offsetWidthoffsetHeightoffsetTopoffsetLeft
  • scrollWidthscrollHeightscrollTopscrollLeft
  • widthheight
  • getComputedStyle()
  • getBoundingClientRect()

因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。

如何避免

CSS

  • 避免使用table布局。
  • 尽可能在DOM树的最末端改变class
  • 避免设置多层内联样式。
  • 将动画效果应用到position属性为absolutefixed的元素上。
  • 避免使用CSS表达式(例如:calc())。

JavaScript

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
  • 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

拖拽排序

图表

loader里面plugin的区别

作用不同:

  • Loader直译为”加载器”。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
  • Plugin直译为”插件”。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

用法不同:

  • Loader在module.rules中配置,也就是说作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
  • Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。

webpack

小程序

TS

JS里面的eventloop

4.16璇瑞智佳装饰16:00

前端和后端的交互

数组的方法

vuex了解吗

axios用的是封装吗

vue3.0

经常用的框架有哪些

原生的组件库

JQuery如何获取input取值

layui

移动端

页面适配

弹性盒有用过吗

vue里面用了哪些路由

路由守卫有哪几种

vue的生命周期用过哪些

小程序有没有了解

4.17慧禹科技 11:00

rem、em、vh、px

  1. px就是pixel(像素)的缩写,相对长度单位,相对于屏幕分辨率。

  2. em参考物是父元素的font-size,具有继承的特点。浏览器默认字体是16px,整个页面内1em不是一个固定的值。字体大小同样都是1.5em,但是效果却截然不同,按照W3C提供的公式,我们可以计算下: class为id1的div字体大小继承自父元素body:16px1.5em = 24px class为id2的div字体大小继承自父元素id1:24px1.5em = 36px class为id3的div字体大小继承自父元素id2:36px*1.5em = 54px

  3. rem是CSS3新增的一个相对单位,但相对的只是HTML根元素。通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。

  4. % 百分比,相对长度单位,相对于父元素的百分比值

    元素宽高与字体大小使用区别:

    (1)尽量使用相对尺寸单位

    使用相对尺寸单位计量,则在调整页面的布局的时候,不需要遍历所有的内部DOM结构,重新设置内部子元素的尺寸大小。如果是随着父容器或者是整体页面布局而改变尺寸,则使用%更好,如元素的高度和宽度设置。

    (2)字体尺寸尽量使用em、rem

    为了字体大小的可维护性和伸缩性,推荐使用em,如果存在3层以及3层以上的字体相对尺寸的设置,可以考虑使用rem。

  5. vm、vh、vmin、vmax是一种视窗单位,也是相对单位。它相对的不是父节点或者页面的根节点。而是由视窗(Viewport)大小来决定的,单位 1,代表类似于 1%。 视窗(Viewport)是你的浏览器实际显示内容的区域—,换句话说是你的不包括工具栏和按钮的网页浏览器。

    具体描述如下:

    vw:视窗宽度的百分比(1vw 代表视窗的宽度为 1%)
    vh:视窗高度的百分比
    vmin:取当前Vw和Vh中较小的那一个值
    vmax:取当前Vw和Vh中较大的那一个值

    vh和vw相对于视口的高度和宽度, 1vh 等于1/100的视口高度,1vw 等于1/100的视口宽度 比如:浏览器高度900px,宽度为750px, 1 vh = 900px/100 = 9 px,1vw = 750px/100 = 7.5 px, 很容易实现与同屏幕等高的框。

Javascript常用的几种创建对象的方式

  1. {}
  2. new Object()
  3. 使用字面量
  4. 工厂模式
  5. 构造函数模式(constructor)
  6. 原型模式(prototype)
  7. 构造函数+原型模式

前端向后端发送请求遇到500

503错误是什么原因

1、站点遭到攻击,在超过限制时报503错误,待攻击停止就可以恢复了;

2、站点规模较大,并发请求过多,这种建议修改优化程序或需要升级更高类型主机;

3、程序有错误,在短时间内产生多次工作进程崩溃,会因IIS7的快速故障防护功能而关闭程序池;

4、站点提供下载,当带宽超过限制时会报错,需停止下载功能,或者升级主机解决。

在vue的基础上封装的UI

python了解吗

技术栈:

pc:avue

移动端:uni-app

后台:spring boot

4.19科脉技术10:00

介绍一下电商后台管理系统,如何实现

input组件如何封装实现双向绑定

后台的数据如何处理

接口格式、权限控制如何处理,后端是否会返回一个权限状态码,在哪处理

前端:iview

后端:java

4.19新晨科技14:00

对promise的理解,有什么特征

promise.then()可以继续then吗

它的状态可以保持吗

vue的生命周期有什么特点

传参方式有哪些

父子组件通讯

vue路由如何传参

vue中路由中需要传递参数的话可以用query和param传递,两者类似于get和post。

下面来说下vue自带的路由传参的三种基本方式

先有如下场景 点击当前页的某个按钮跳转到另外一个页面去,并将某个值带过去

1
<div class="examine" @click="insurance(2)">查看详情</div>

第一种方法 页面刷新数据不会丢失

1
2
3
4
5
6
7
methods:{
insurance(id) {
//直接调用$router.push 实现携带参数的跳转
this.$router.push({
path: `/particulars/${id}`,
})
}

需要对应路由配置如下:

1
2
3
4
5
{
path: '/particulars/:id',
name: 'particulars',
component: particulars
}

可以看出需要在path中添加/:id来对应 $router.push 中path携带的参数。在子组件中可以使用来获取传递的参数值
另外页面获取参数如下

1
this.$route.params.id

第二种方法 页面刷新数据会丢失

通过路由属性中的name来确定匹配的路由,通过params来传递参数。

1
2
3
4
5
6
7
8
9
methods:{
insurance(id) {
this.$router.push({
name: 'particulars',
params: {
id: id
}
})
}

对应路由配置: 注意这里不能使用:/id来传递参数了,因为组件中,已经使用params来携带参数了。

1
2
3
4
5
{
path: '/particulars',
name: 'particulars',
component: particulars
}

子组件中: 这样来获取参数

1
this.$route.params.id

第三种方法
使用path来匹配路由,然后通过query来传递参数
这种情况下 query传递的参数会显示在url后面?id=?

1
2
3
4
5
6
7
8
9
methods:{
insurance(id) {
this.$router.push({
path: '/particulars',
query: {
id: id
}
})
}

对应路由配置:

1
2
3
4
5
{
path: '/particulars',
name: 'particulars',
component: particulars
}

对应子组件: 这样来获取参数

1
this.$route.query.id

组件中 获取参数的时候是route.params

用过哪些布局flex有什么特点

es6知道哪些

数组过滤

数组快速拷贝 Object.asign

如何根据元素class获取id,dom操作

盒子模型

定位方式有哪些,position相对于什么

• position: relative 相对定位,相对定位不脱离文档流,参考其在原来文档流中的位置,通过 top,bottom,left,right 定位,并 且可以通过z-index进行层次分级。

• position: absolute 绝对定位,绝对定位脱离文档流,依据最近的已经定位(绝对、相对或固定定位)的父元素,通过 top,bottom,left,right 定位。当父级 position 为 static 时,absolute元素将依据body根元素(浏览器窗口)进行定 位,可以通过z-index进行层次分级。

• position: fixed 固定定位,固定定位与父元素无关(无论父元素是否定位),直接根据浏览器窗口定位,且不随滚动条拖动 页面而滚动,可通过z-index进行层次分级。

• position: sticky 粘性定位,该定位基于用户滚动的位置。它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。

什么是跨域,有什么特征

现代浏览器出于安全考虑,都会去遵守一个叫做“同源策略”的约定,同源的意思是两个地址的协议、域名、端口号都相同的情况下,才叫同源。这个时候两个地址才可以相互访问 cookie、localStorage、sessionStorage、发送 ajax 请求,如果三者有一个不同,就是不同源,这时再去访问这些资源就叫做跨域。

跨域的解决方法

1、JSONP (JSON with padding)

就是与后端协商好,在请求数据返回数据的时候以字符串的格式返回。

1
2
3
4
script src = 'xxx.com'  callback = showDate
function showDate (ret) {
console.log(ret)
}

这个时候就跨域了,JSONP 可以在IE10以下的浏览器去获取数据。

2、CORS (跨资源共享)

在响应头里面写上

1
res.setHeader(' Access - Contorl - Allow - Origin' ,'http://localhost:8080')

只要响应头里面的Origin里面本域(协议、域名、端口)一样,就可以接受到数据

3、降域和PostMessage

3.1 降域

1
document.domain = 'xxx.com'

需要本域中的域名和端口一样

3.2 PostMessage

1
2
window.frames[0],PostMessage(this,value)
window.addEventListener('message',function(e)){} //调用message,监听对方发送的消息

如何进行开发调试连接后端如何配置

vuex用来做什么

4.20 博彦科技 9:30

vue的生命周期的具体含义

vuex的用法

es6的新特性

4.20力格软件10:30

小程序有涉及吗

cookie、session storage、localstroage

有没有处理过数据量大的页面速度方面

技术栈:用react-native开发app

4.20振翕科技15:00

浏览器是如何运行的

前端的开发环境有自己搭建吗

对es6了解吗

为什么要用箭头函数

用echart做了什么

vue的路由用哪些

兄弟组件之间传参方式

父子组件之间

vuex有哪些属性

跨域怎么实现

布局、定位、伪类熟悉吗

响应式布局

对微信小程序了解吗

4.21二航院 10:30

等了一小时,无技术面

4.21东天红数科 15:00

js的数据类型有哪些

symbol的用法有了解吗

let、const、var区别

简单介绍一下变量提升

js的DOM和BOM分别是什么

首先我们来分别看一下bom和dom的概念

1、BOM是浏览器对象模型

提供了独立于内容而与浏览器窗口进行交互的对象。描述了与浏览器进行交互的方法和接口,可以对浏览器窗口进行访问和操作,譬如可以弹出新的窗口,改变状态栏中的文本,对Cookie的支持,IE还扩展了BOM,加入了ActiveXObject类,可以通过js脚本实例化ActiveX对象等等)

2、DOM是文档对象模型

DOM是针对XML的基于树的API。描述了处理网页内容的方法和接口,是HTML和XML的API,DOM把整个页面规划成由节点层级构成的文档。DOM本身是与语言无关的API,它并不与Java,JavaScript或其他语言绑定。

看完了js中bom和dom的概念后,我们应该可以很容易就能够总结出关于js中bom和dom的区别

js中bom和dom的区别之一:

1、BOM是Browser Object Model的缩写,即浏览器对象模型。

BOM和浏览器关系密切。浏览器的很多东西可以通过JavaScript控制的,例如打开新窗口、打开新选项卡(标签页)、关闭页面,把网页设为主页,或加入收藏夹,等等…这些涉及到的对象就是BOM。

2、DOM是Document Object Model的缩写,即文档对象模型。

DOM和文档有关,这里的文档指的是网页,也就是HTML文档。网页是由服务器发送给客户端浏览器的,无论用什么浏览器,接收到的HTML都是一样的,所以DOM和浏览器无关,它关注的是网页本身的内容。由于和浏览器关系不大,所以标准就好定了。

js中bom和dom的区别之二:

1、BOM没有相关标准。

由于没有标准,不同的浏览器实现同一功能,可以需要不同的实现方式。对于上面说的功能,不同的浏览器的实现功能所需要的JavaScript代码可能不相同。

2、DOM是W3C的标准。

既然有标准了,大家就要按标准来了。

js中bom和dom的区别之三:

1、BOM的最根本对象是window。

2、DOM最根本对象是document(实际上是window.document)。

最后,需要说明的是:

1、虽然BOM没有一套标准,但是各个浏览器的常用功能的JavaScript代码还是大同小异的,对于常用的功能实际上已经有默认的标准了。所以不用过于担心浏览器兼容问题,不是每个浏览器都有自己的BOM,也不需要为每个浏览器都学习一套BOM,只是个别浏览器会有新增的功能会在BOM上体现出来。

2、我们知道HTML是由标签组成的,标签套标签。JavaScript可以通过DOM获取到底有哪些标签,标签里面的属性是什么,内容是什么等。

如何创建一个表格

vue开发组件的步骤,采用什么方式比较合理

有没有用过vuex与data处理数据有什么异同点

vuex出现页面刷新的问题如何处理

vue-cli的工具用过什么,配置

vue-router用过哪些、路由生命周期

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传

created、mounted的区别

跨域了解吗

事件循环eventloop

promise

node用的多吗

login登陆的方式模型

axios拦截器

简单介绍一下计算属性,什么时候用到

webpack用过多少

举例说明数学对算法的影响

4.22 北京富基融通信息9:30

招中级,无技术面

可以提前了解公司背景,技术栈

4.22群光广场14:00

delete和vue.delete的区别

delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
Vue.delete 直接删除了数组 改变了数组的键值

减少页面加载数据时间的方法

HTML:减少页面加载时间的方法

display:none和visibility:hidden的区别

  1. 是否占据空间

display:none,该元素不占据任何空间,在文档渲染时,该元素如同不存在(但依然存在文档对象模型树中)。
visibility:hidden,该元素空间依旧存在。
即一个(display:none)不会在渲染树中出现,一个(visibility :hidden)会。

  1. 是否渲染

display:none,会触发reflow(回流),进行渲染。
visibility:hidden,只会触发repaint(重绘),因为没有发现位置变化,不进行渲染。

  1. 是否是继承属性

display:none,display不是继承属性,元素及其子元素都会消失。
visibility:hidden,visibility是继承属性,若子元素使用了visibility:visible,则不继承,这个子孙元素又会显现出来。

  1. 读屏器是否读取

读屏器不会读取display:none的元素内容,而会读取visibility:hidden的元素内容。

keep-alive的作用

vue的响应式原理

垂直居中、水平居中的方式

4.22卓信数据16:30

垂直居中的方式

js的数据类型

深拷贝、浅拷贝

this的指向

有哪些方法可以改变this的指向

call、apply

js的继承

vue的生命周期

状态管理vuex

组件之间的通讯传值

虚拟dom了解吗

项目里面的性能优化

对vue里面的插件封装有没有实战

往后台发送数据用同步还是异步

await的目的是什么

请求数据比较耗时的情况下如何处理保证交互的

请求数据过程中当前客户端的交互方式有什么优化

Web前端性能优化——如何提高页面加载速度

hash和history模式的区别

Hash模式

  • 早期的前端路由的实现就是基于location.hash来实现的,location.hash的值就是URL中#后面的内容 其实现原理就是监听#后面的内容来发起Ajax请求来进行局部更新,而不需要刷新整个页面。
  • 使用hashchange事件来监听 URL 的变化,以下这几种情况改变 URL 都会触发 hashchange 事件:浏览器前进后退改变 URL、<a>标签改变 URL、window.location改变URL。

优缺点

  • 兼容低版本浏览器,Angular1.x和Vue默认使用的就是hash路由
  • 只有#符号之前的内容才会包含在请求中被发送到后端,也就是说就算后端没有对路由全覆盖,但是不会返回404错误
  • hash值的改变,都会在浏览器的访问历史中增加一个记录,所以可以通过浏览器的回退、前进按钮控制hash的切换
  • 会覆盖锚点定位元素的功能
  • 不太美观,#后面传输的数据复杂的话会出现问题

History模式

  • history 提供了 pushStatereplaceState 两个方法来记录路由状态,这两个方法改变 URL 不会引起页面刷新
  • history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或<a>标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和<a>标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
  • pushState(state, title, url)replaceState(state, title, url)都可以接受三个相同的参数:
  • state:需要保存的数据,这个数据在触发popstate事件时,可以在event.state里获取
  • title:标题,基本没用,一般传 null
  • url:设定新的历史记录的 url,新的 url 与当前 url 的 origin 必须是一样的,否则会抛错,url可以是绝对路径,也可以是相对路径。

优缺点

  • 使用简单,比较美观
  • pushState()设置新的URL可以是任意与当前URL同源的URL,而hash只能改变#后面的内容,因此只能设置与当前URL同文档的URL
  • pushState()设置的URL与当前URL一模一样时也会被添加到历史记录栈中,而hash#后面的内容必须被修改才会被添加到新的记录栈中
  • pushState()可以通过stateObject参数添加任意类型的数据到记录中,而hash只能添加短字符串
  • pushState()可额外设置title属性供后续使用
  • 前端的URL必须和向发送请求后端URL保持一致,否则会报404错误
  • 由于History API的缘故,低版本浏览器有兼容行问题

image-20210425211705851

有移动端的项目经验吗

闭包和普通函数的区别

对css的盒模型有什么了解

对前端、vue的学习难点

向后端是如何调取接口

有没有用vue做过树形、个性化搜索

head请求头全局定义

获取到用户权限之后,有没有做过本地化缓存

跨域的原因

sessionstorage和localstorage的区别

4.25百度 19:00

垂直居中

vue的生命周期

对闭包的理解

原型和原型链

父子组件传值

vuex

自动化测试

小程序

jquery

http的状态码

解决跨域的方法

从浏览器输入地址到看到页面的过程

es6有哪些新特性

this的指向

this 永远指向最后调用它的那个对象

改变 this 的指向我总结有以下几种方法:

  • 使用 ES6 的箭头函数
  • 在函数内部使用 _this = this
  • 使用 applycallbind
  • new 实例化一个对象

箭头函数的 this 始终指向函数定义时的 this,而非执行时。箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

技术栈:vue、react、jquery

4.26博垠10:30

前端开发都做了哪些事情

用什么软件开发

uniapp听说过吗

熟悉哪些模式的接口

知道前端的一些效果吗,划线,图像

图表类

界面有没有从效果图切图实现静态页面

做前端的优势在哪

技术栈:uniapp

4.26众创网 14:00

没有实际的项目

平时有看什么书

vue用的脚手架开发的打包命令

有对接过接口吗

微信这一块有接触吗

有没有遇到过盒子塌陷

前端的优化方式有哪些

token验证是如何处理的

技术栈:vue、elementUI、layUI

4.27墨霖教育 9:30

GET和POST的区别,何时使用POST?

1.GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符

2.GET: 传送的数据量较小,不能大于2KB。post 传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。 用IIS过滤器的只接受get参数,所以一般大型搜索引擎都是用get方式

3.GET:是从服务器上获取数据,post 是向服务器传送数据。 get 请求返回 request – URI 所指出的任意信息。

4.GET:是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址,用户看不到这个过程。

5.POST:一般用于修改服务器上的资源,对所发送的信息没有限制。

6.GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。

然而,在以下情况中,请使用 POST 请求:

无法使用缓存文件(更新服务器上的文件或数据库)

向服务器发送大量数据(POST 没有数据量限制)

发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

标准盒子模型

清除浮动

安卓和ios熟悉吗

dp、sp、px单位互算有了解吗

4.29贝联教育 10:30

了解HTML5、CSS3新特性

清除浮动的方式

圣杯布局、双飞翼布局

js的基本数据类型

undefined和null的区别

数组去重的方法

操作数组的方法有哪些

es6的新特性

let和const的区别

箭头函数this的指向

promise里面有哪些

flex有哪些属性

flex是哪些属性的缩写

冒泡排序的原理

说一下ajax的原理

浏览器从输入url到页面渲染完成有哪些过程

v-if和v-show的区别

v-for里面的key属性

说一下vue的生命周期,分别在什么时候触发

created里面可以操作dom吗,不可以

watch和computed的区别

data为什么是一个函数

router有哪些钩子函数

如何实现守卫

有用用户权限吗

后台管理里面权限有深入了解吗

vuex用过吗

webpack自己有配置吗