前端知识点

169 阅读21分钟

1)h5 暂未完善

2)css3 暂未完善

3)es6

3.1 数组有哪些常见方法

追加元素 unshift push

移除元素 shift pop

查找元素 find findIndex indexOf includes

数组检测 some every

截取数组/替换数组元素 slice splice

数组循环 map forEach

过滤数组 filter

数组求和 reduce

数组合并 concat

数组排序 sort

数组反转 reverse

转换成对应的字符串 join

数组扁平化 flat(infinty)

用的比较多的:

push 追加元素

map 批量删除多选后,通过map将选中列表里的ID提取出来

splice 对表单里的表格点删除的时候,移除表格某行

3.2 原型和原型链

原型:原型是函数所独有,比如你定义的常规对象或者数组上面不能加prototype。

原型链:当访问一个对象的方法时,如果自身存在的话,直接用自身上面的。如果自身不存在,就会沿着它的__proto__指针指向的原型对象上继续查找。由于原型也是一个对象,也有__proto__属性,当它上面没有这个方法,就会继续往上一层层查找,一直找到null(原型链顶端为止),如果还没找到就报错【xxx() is not a function】,这一条线就称为原型链。

3.3 闭包

概念:闭包是有权访问一个局部作用域里面变量的函数。

形成要素:1、函数嵌套,2、内部函数引用了外部函数的变量。

使用场景:

1、回调函数【比如:setTimeout传递的函数不能带参数,而通过闭包可以完美解决】

2、变量私有化【作用:消除全局变量污染的弊端,防止团队开发之间的变量冲突和覆盖】

3、函数柯里化【将多参数函数转化为一系列接受单一参数的函数】

4、模块化【作用:将不同的功能隔离在不同的模块】

缺点:没有垃圾回收机制,使用过多会导致内存泄露。

解决:将函数赋值为null。

3.4 判断变量的类型方法

typeof 判断基本类型

intanceOf 判断复杂类型

变量.constructor == String | Array | Object ....

Object.prototype.toString.call 通用型判断

判断数组

不推荐 arr intanceOf Array, arr.constructor === Array

推荐 Array.isArray(arr)

兼容低版本浏览器 Object.prototype.toString.call(arr) === '[array Object]'

最终方案

function isArray(arr) {
    return typeof Array.isArray == 'function' ? 
        Array.isArray(arr) : 
        Object.prototype.toString.call(arr) === '[array Object]'
}

3.5 es6的一些新特性

新增了let const,它们具有块作用域,在同一作用域内不能重复定义。const定义基本类型不能再次更改,定义引用类型可更改里面的属性,但不能更改本身,如果想让它不能更改属性可以通过Object.freeze冻结。同时,vue3里面定义响应式对象state推崇const定义,为了防止响应式被替换丢失链接。

新增了箭头函数,简化了定义函数的写法,同时不需要多定义一个变量来存放this。

新增了promise,async awite解决了地狱回调的问题。

新增了解构赋值,可以从数组和对象中提取值,对变量进行赋值。

新增了class类,用以替代之前的function.prototype相关的操作。

新增了Reflect和Proxy。

Reflect(反射):他提供了一套统一操作Object的API。

比如之前判断对象是否包含某个属性,通过属性 in obj;删除某个属性用delete obj.属性;读取属性用对象.属性。

而如果用Reflect的话:判断是否包含用Reflect.has;删除某个属性用Reflect.deleteProperty;读取属性用Reflect.get。用Reflect可以使这些操作看起来更加统一。

Proxy(代理):用来创建一个代理对象。

proxy的好处:

1、vue3底层用的proxy代理的方式,直接监听整个对象,不需要像vue2那样递归的创建Object.defineProperty。

2、它可以监听一些Object.defineProperty监听不到的操作,比如监听对象属性的新增、删除等。

3.6 事件循环

由于js是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,所以会先将同步代码压入执行栈中,依次执行,将异步代码推入任务队列,任务队列又分为宏任务队列和微任务队列,因为宏任务队列的执行时间较长,所以微任务队列要优先于宏任务队列先执行。微任务队列的代表就是Promise.then、 this.$nextTick,宏任务的话就是setTimeout、setInterval。

3.7 异步编程 promise,async await

promise为了解决地狱回调,支持链式调用,每次执行完都返回一个新的pormise对象。

async 返回一个promise对象,await 是等待一个异步方法执行完成,用来代替promise.then。

如果需要依次调用多个接口,用await更合适。await最好通过try catch来捕获异常,不然报错会阻塞下面代码的执行。

什么区别?

1、async/await使得异步代码看起来像同步代码

2、async函数可以让代码简洁很多,避免了嵌套代码

3、promise是es6新特性,async await是es8新特性

3.8 this指向,call、apply、bind的区别

this指向:

-----js里面的this:

通常情况下,谁调用this就指向谁,但是这也跟this的执行环境有关。比如去调用一个对象里面的箭头函数或者通过call、apply、bind的方式去调用,结果就会不一样。

this的具体指向有这几点:

1、全局里的this和一般函数里的this都指向window

2、箭头函数里没有this,它的this指向是根据外层作用域决定

3、事件函数中的this指向绑定事件的元素

-----框架里面的this:

1、vue里面的@click中的this指向当前的vue实例

2、react里面的onClick里面的this指向绑定事件的元素。如果想让它去指向当前class的话需要用箭头函数,或者用bind改变指向

call、apply、bind:

相同点:都可以改变this指向

不同点:

   1、调用不一样,call和apply会调用函数,而bind不会立即调用函数
   2、传递的参数不一样,call是通过","依次传递,而apply是通过数组传递,bind也是通过","传递,
   且可以传递两次参数

应用场景:

  call: 继承、判断复杂类型
  apply: 经常跟数组有关系,比如手写防抖节流
  bind: 
      1、改变定时器的this指向。
      2、组件调用时候的参数占位。查询表格的时候,在search方法里有一个是否重置分页的参数,默认为true。然而在表格组件里
      点击分页的时候不能再让分页重置为1。所以外部传递给组件分页方法的时候,先指定值
      为this.search.bind(this, false)进行占位,组件里面直接调用分页方法即可。
      3、在react中的constructor里,改变对象里面函数的this指向。

3.9 什么是深拷贝,什么是浅拷贝

浅拷贝:如果属性是基本类型,拷贝的是基本类型的值,如果是引用类型,拷贝的就是内存地址,如果其中一个对象改变了这个地址,就会影响到另一个对象。

浅拷贝实现方式:
1、扩展运算符... -->> let obj1 = {...obj2}
2、Object.assign -->> Object.assign(this.form, data.list)

浅拷贝应用场景:
点击编辑的时候,需要先查询详情,在子组件里面调用接口拿到数据后,通过
Object.assign(this.form, data.data)赋值给form表单

深拷贝:会拷贝所有的属性,拷贝前后两个对象不会相互影响。

深拷贝实现方式:
1、lodash里面的_.cloneDeep
2、自己通过递归封装一个cloneDeep方法
3JSON.parse(JSON.stringify(obj))【一般不推荐,因为如果obj里面存在时间对象,序列化
后会变成字符串;如果obj里有函数、undefined,则序列化的结果会把函数、undefined丢失】

深拷贝应用场景:
1、提交表单的时候,有时需要对form对象的数据进行处理,如果直接操作的话,会影响到页面变化。可以通过深拷贝先存储后再处理。
2、父组件传递给子组件引用类型的数据,子组件发生了更改,会影响到父组件。如果不想让其受影响,可以在子组
件的created方法中进行深拷贝,用另一个变量作为承载,这样就不会影响父组件了。

3.10 什么是防抖节流

防抖:当某一个时间段内多次触发同一事件时,只执行最后一次触发的事件。其余的事件都会被清除。

应用场景:

就类似于淘宝的商品搜索,如果没有使用防抖,可能输入100下面出现一堆101、102...。因为ajax是异步操作,在你输入10的时候向后端发送了请求,然后后端通过模糊查询匹配到了101、102返给了前端,这个时候用户刚好又输入了一个0。

节流:在某一个时间段内事件只能被触发一次并执行,如果想再次触发执行需等待下一个时间周期。

应用场景:

高频监听事件 (如:按钮点击、鼠标移动)

3.11 递归

概念:自己调用自己。

使用场景:

由于不确定系统左边是几级菜单,所以需要menu和menu-item两个组件,在menu组件里面循环调用menu-item组件,然后在menu-item里面判断如果menuData.children.length > 0,就再调用自身。

缺点: 递归层级太深会导致栈溢出。

3.12 设计模式

1、原型模式:通过克隆一个已有对象来生成新对象。

2、工厂模式:通过工厂方法创建对象,而不是直接使用 new 操作符。

3、单例模式:确保一个类只有一个实例,并提供全局访问点。

4)vue

4.1 vue的双向绑定原理

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

4.2 vue中的data为什么是一个函数

1、每个组件都是vue的实例。

2、组件共享data属性,当data的值是一个引用类型的时候,改变其中一个,会影响到其他。

3、组件中的data写成一个函数,这样每次复用组件,都会返回一份新的data,让各个组件实例维护各自的数据。

4.3 vue的生命周期

1、beforeCreate 创建前 --》加loading事件

2、created 创建后 --》适合初始化、异步请求接口。

3、beforeMount 挂载前

4、mounted 挂载后 --》做一些操作dom的业务逻辑,比如拿到数据后渲染echarts。

5、beforeUpdate 更新前

6、updated 更新后 --》处理统一变化的数据。

场景:在查询表格的时候有一个loading状态,请求接口之前设置loading状态为true,然后拿到数据之后设置loading状态为false。但是我们需要考虑一个问题,网卡的时候接口一直没有响应怎么办?由于loading加载的时候,改变了this.loading的值,会触发update生命周期,所以我们可以在update生命周期进行处理,让它10秒后关闭loading状态。

// 如果this.loading的值为true
if (this.loading) {
  // 清除时钟
  clearTimeout(this.timer)
  // 给时钟赋值,6秒之后关闭loading状态
  this.timer = setTimeout(() => {
    this.loading = false
  }, 10000)
} else {
  // 如果this.loading属性为false,代表表格数据已经请求完成,清除时钟
  clearTimeout(this.timer)
}

7、beforeDestroy 销毁前 --》可以做一个是否删除的确认框

8、destroyed 销毁后 --》 销毁定时器,解绑事件监听等

9、activated 组件激活

10、deactivated 组件停用

父子生命周期

第一次加载:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

4.4 组件传参

父子组件

父传子 prop refs.name.子方法(id) | provide inject

子传父 emit parent

兄弟组件 eventBus

解决传参的复杂和混乱问题 vuex

4.5 v-if 和 v-show的区别

相同点:都可以做到显示隐藏

不同点:

v-if 适用于页面第一次渲染,因为不满足条件不会渲染dom。

v-show 适用于动画的频繁切换,因为每一次更改的只是display的值。

业务场景:

1、如果是做系统里的弹窗表单的话,我会选择v-if。因为v-if会重新跑一遍表单组件的生命周期,可以将整个表单内容,完完全全进行重置。

2、如果是做小程序的身份验证,我会选择v-show。因为它可能有上一步、下一步,我将上一步、下一步的操作页面封装成组件,然后在外部通过v-show去控制,这样就不会出现数据丢失。

4.6 谈谈vuex

概念:

1、用于多个组件之间的状态共享。

2、解决了组件开发中,传参的复杂和混乱问题。

5个属性 state,getter,action,mutation,module

state 存放共享数据

getter 格式化数据

mutation 只能包含同步操作,是更改state的必经之路,通过this.$store.commit

action 也可更改store,不过是提交到mutation,并且可以包含异步操作,在组件中是this.$store.dispath,在vuex中是通过commit调用mutation

module 项目复杂的时候需要分子模块去管理,比如一般系统会有user和common两个子模块:

1、user 后台系统的故障单、保留单、返厂单在新增时需要添加提出者,并默认为当前用户。而你每次都调用getUserInfo接口获取用户名比较浪费效率,而将用户信息存储到vuex里面,然后通过this.$store.state.user.username去拿用户名即可。

2、common 里面可以对侧边栏、左侧菜单、标签页等数据的操作,进行统一的管理。

4.7 computed和watch的区别

computed 为了简化template里面的计算复杂度,具有缓存属性,定义的变量不在data里面声明。

使用场景:

1、做购物车的时候,配合reduce计算总价。

2、比如我之前做的一个系统,在新增合同的时候,需要先选择合同单元,然后填写每一项的服务面积和租金单价,下面通过computed,动态的回显不含管理费的月租单价和月租总价。

watch 用来监控vue实例的变化,检测一个数据影响多个数据的情况。

使用场景:

1、监控路由的改变,比如点击系统左边的菜单,右上角需要新增一个tab标签。我们可以在watch里面监听route,然后给这个tab的名称设置为菜单名称。

2、监听表单选项的改变,比如在form表单里面选择服务类别,如果选择了其他这个选项,就让其他类别的那个文本框显示,然后可以去填写其他的服务内容。我们可以在watch里面去监听选项的值,然后进行处理。

4.8 v-for循环为什么一定要绑定key

为了高效的渲染虚拟dom。比如往一个列表里面插入元素,如果没有唯一key的话,重新渲染的时候会造成多余的增删节点的操作。而加上唯一key之后,在diff算法比对节点的时候能够准确的定位,将原来的复用,新的节点插入。同时不能把index作为key值,因为index并不是唯一值,下次渲染的时候会造成新的key和旧的key不一致,同样会造成多余的增删节点的操作。

4.9 vue的hash和history模式

1、hash ——即地址栏URL中带#符号。域名后面的是哈希值。虽然出现URL中,但不会被包含在HTTP请求中。

2、history ——会出现404 的情况,需要后台配置。

4.10 diff算法

1、对新旧虚拟dom作对比,将变化的地方更新在真实dom上。

2、diff的执行时刻是组件执行其更新函数时,在patch的过程中去对比新旧节点。

3、diff的过程整体是深度优先,同层比较的策略。借助key通常可以更精确的找到相同的节点,使整个patch过程非常高效。

4.11 vue的nextTick

概念:下一次dom更新后的回调函数。

应用场景:

点击表格编辑的时候,会弹出一个表单,表单的显示和隐藏我们是在子组件内部通过v-if进行控制。通过this.$refs.name.openDialog打开弹窗,在方法openDialog里将开关的值设置为true,由于v-if从隐藏到显示需要时间,如果这个时候我们直接调接口给form进行赋值。可能子组件的dom还没加载完,就会造成赋值异常的情况。所以需要通过nextTick,在dom加载完后再去给form进行赋值。

4.12 vue组件化理解

1、组件是vue的核心特性之一,组件化开发可使程序提升开发效率、通用性等。

2、组件按分类有

页面组件【也叫做单页,一个页面就是一个组件,只完成功能,不复用】

业务组件【实现某一业务的组件,比如根据公司业务,定制化封装的table、form、upload等组件】

通用组件【弹窗、分页组件等】。

3、vue中常见的组件化技术有:prop、自定义事件、插槽。它们主要用于组件通讯、扩展。

4、公共组件应该是高内聚、低耦合的。

作用:可以使组件使用变得灵活,从而可以提高组件的复用性。

好处:

①、将业务代码放在组件外部处理可以避免改动一个界面影响到其他的页面,防止出现改动一个小需求崩溃整个系统的情况。如果测试环境没检测到bug,上线了之后问题就大了。

②、可以有效的防止代码冲突,由于开发项目一般是团队开发的方式。如果同事小张和小李都把业务代码都写在组件里面, 当他们操作了同一个文件的同一位置的时候,提交代码可能发生冲突的情况。

③、公共组件要在不断沉淀的过程中,能保持一直复用的原则【不仅仅局限于当前系统】,如果组件里写一大堆业务代码,放到下个系统的时候,会影响可读性,和出现一些意料之外的bug。

如何去封装一个组件?

先进行共性需求提取和需求分析,然后满足当下已经出现的需求点,留出未来可能出现的扩展点。业务组件的模板解析一般放在组件内而不是通过插槽的方式对外暴露,当然我们也可以预留对应的插槽。

比如table、form组件我们一般是将解析放在组件内部,一是template那块代码看起来更整洁,二是可以将column配置项提取到单独文件里面进行管理。

而对于像弹窗组件、订单内容展示组件,一般是必须要通过插槽去处理的。

4.13 vue的性能优化

1、路由懒加载、图片懒加载【手写或借助vue-lazyload】

2、keep-alive组件缓存

3、webpack打包优化,比如(小图片转换base64,减少http请求)

4、将UI框架进行按需引入,比如element-ui、ant-design

5、使用cdn加载第三方模块

项目中所用到的优化

1、对图片进行压缩和懒加载。

2、对详情页和一些子页面使用分包。

3、采用缓存策略,比如选择类别界面,不要每次进入都调用接口请求列表,可以将它缓存起来。

4、对搜索按钮、表单提交按钮使用节流减少http请求。

5、在onShow和onHide生命周期,只做必要的操作,避免执行冗余的代码。

4.14 vue2和vue3

4.14.1 vue2和vue3的区别

1、生命周期不一样 --》 vue3新增了组合式开发模式,beforeCreate created改成了setup,mounted改成了onMounted

2、指令不一样 --》 vue2是v-for优先级更高,vue3是v-if的优先级更高

3、开发模式不一样 --》 vue2只有选项式开发模式,vue3可以使用组合式和选项式。

4、响应式原理不一样 --》 vue2是通过object.defineproperty实现响应式,vue3是通过proxy实现响应式。

4.14.2 对vue3的新特性的理解

1、性能提升 --》 打包大小减少了40%,内存大小减少了一半左右。

2、源码升级 --》 虚拟dom的重写,静态属性提升,是基于proxy的响应式系统。

3、更容易维护 --》 ts底层重写,使其拥有强有力的的类型检查和语法提示。

4、项目结构更清晰 --》 自定义hook可以将多个功能进行拆分。

4.15 vue和react的区别

数据流:

vue 思想是响应式的,也就是基于是数据可变的。通过对每一个属性建立Watcher来监听,当属性变化的时候,响应式的更新对应的虚拟dom

react 主张函数式编程,所以推崇纯组件,数据不可变

使用方面:

vue 自动挡

1、渲染列表:v-for

2、监听用户的输入内容以更新数据:v-model【语法糖,内部集成了:value和@input,是通过 :value="myValue" + @input="myValue=$event.target.value" 实现的】

react 手动挡

1、渲染列表:map => return fun() => fun里面渲染内容

2、监听用户的输入内容以更新数据:value={state.myValue} onChange={this.setValue} => setValue里面this.setState({ myValue : event.target.value })

4.16 后台管理系统中的权限管理是怎么实现的?

1、先在菜单管理添加菜单和按钮(选择菜单类型【目录、菜单、按钮】、上级菜单【树状列表】、菜单名称、菜单图标、授权标识等。)

2、然后在角色管理添加角色,点角色授权:弹出一个权限设置的表单,通过勾选的方式去设置该角色能看到的菜单和按钮。

3、再到用户管理给某个用户去赋予哪些角色,赋予完后就有了这些角色的权限。

4、当用户登录进来的时候,接口返回的routeList就是之前赋予的路由权限,然后通过addRoute动态添加路由,并渲染系统左边的菜单列表。

5、最后用户进入某个界面的时候,给页面里的按钮通过v-permission进行权限控制, 当缓存里的permissions没有包含某个按钮的权限,就会remove掉这个按钮。

5)浏览器

5.1 页面上输入一个url发生了什么?

1、通过dns解析查找对应的ip地址

2、浏览器向服务器发送对应的http请求

3、服务器处理请求,返回一个http响应

4、浏览器进行dom树构建

5、完成显示页面

5.2 http状态码分别代表什么

2xx 表示http请求已经处理完成

3xx 表示请求的资源重定向(301永久重定向,302临时重定向)

4xx 表示客服端错误(400参数格式错误,401token失效,403无权限,404资源路径错误)

5xx 表示服务端错误 (500接口报错【出现的情况很多,比如1、请求头部格式不匹配,2、后端代码层面报错,3、执行sql语句的时候出错了】,504网关超时)

5.3 什么是同源协议,怎么解决跨域?

同源协议:

是浏览器的一种安全机制,用来限制不同源的网站不能通讯,指的是域名、端口、协议三者统一。

解决跨域:

1、jsonp:本质是script标签,只支持get请求。需要传入callBack回调函数,后端也要有这个回调函数

2、proxy代理:在vue的配置文件下面配置devServer下面的proxy,指定代理

3、nginx代理:nginx.conf文件里的server下设置 proxy_pass 你要代理的域名

4、后端解决:配置请求头Access-Control-Allow-Origin的值(*为任何域名都可跨域,或设置指定域名)

5.4 tcp连接【问的较少】

tcp 的自身特点:可靠传输。客户端和服务端要进行可靠传输,那么就需要确认双方的接收和发送能力。第一次握手可以确认客户端的发送能力,第二次握手,确认了服务端的发送能力和接收能力,所以第三次握手才可以确认客户端的接收能力。不然容易出现丢包的现象。

5.5 浏览器的缓存原理【问的较少】

强缓存 根据过期时间来决定是需要使用缓存还是向服务器获取资源

协商缓存 无论如何都会向服务器发起请求来获取资源

强缓存策略和协商缓存策略

在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息来判断强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器直接使用本地资源的副本,如果协商缓存不命中,则服务器返回最新的资源给浏览器。

5.6 CSRF和XSS攻击

XSS跨站脚本攻击:是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登陆网站时就会执行这些恶意代码,这些脚本可以读取 cookie session token,或者其它敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。

CSRF跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

XSS避免方式:

1、攻击者构建了特殊的URL,当服务器接收到请求后,从URL中获取数据,拼接到HTML后返回,从而导致了恶意代码的执行。所以url参数使用encodeURIComponent方法转义。

2、过滤掉一些不安全的内容,比如用户输入的script、eval节点。

CSRF避免方式:

1、添加验证码

2、使用token验证

服务端给用户生成一个token,加密后传递给用户
用户在提交请求时,需要携带这个token
服务端验证token是否正确

5.7 导致页面白屏的原因

1、JS问题 Vue/React都是依靠JS进行驱动,在渲染页面的时候需要加载很大的JS文件。在JS解析加载完成之前无法展示页面,从而导致了白屏。

2、浏览器兼容问题

3、URL网址无效

5.8 导致页面很卡的原因

原因一:http请求次数太多

解决:使用防抖、节流等方式减少http请求次数。

原因二:接收数据时间过长

解决:图片压缩,后端接口优化。

原因三:JavaScript脚本过大,阻塞了页面的加载

解决:将JavaScript脚本放在页面底部。

script如果没有使用defer【只有IE浏览器支持】,JS文件将在下载后立即执行。这种情况下,script放在顶部会阻塞页面呈现,在网速慢的情况下会导致“白屏”,直到脚本下载完毕才继续呈现页面。

因此,script放在底部可以让页面尽快呈现。

原因四:网页资源过多

解决:可以采取精灵图或者使用CDN部署网络以提高下载速度。

6)小程序

6.1 登录授权

1、在app.vue页面的onLaunch生命周期,去调用wx.login获取code,然后调用接口获取token、手机号等信息。

2、如果没有获取到手机号,证明还未进行授权,就设置缓存值isAuth为flase,然后在首页判断如果isAuth等于false,就给页面添加一个蒙版,点击任何地方都跳转到微信授权绑定手机号界面。

3、在授权页面里点击【手机号一键登录】的时候,将params.detail.encryptedData、params.detail.iv和session_key传给后端解密得到手机号,完成手机号授权。

6.2 生命周期

小程序app中的生命周期

1、onLaunch:小程序初始化的时候调用

2、onShow:初始化后或者切回前台时会触发

3、onHide:切到后台时触发

page页面的生命周期

onLoad:页面加载的时候触发,只触发一次。

onShow:监听页面的显示。

onReady:页面初次渲染之后触发,只触发一次。

onHide:页面隐藏但未卸载的时候触发的,如wx.navigateTo或底部tab切换到其他页面。

onUnload:页面卸载时触发,如wx.redirectTo或wx.navigateBack跳到其他页面时。

6.3 微信支付

1、以企业的身份注册商户号。

2、在微信支付官网给小程序开通微信支付,然后绑定商户号。

3、点击立即支付的时候调用pay方法,在pay方法里先调用获取支付信息的接口,会返回签名、签名类型等信息,然后调用wx.requestPayment。

4、当支付成功的时候会触发success方法,通过wx.redirectTo跳转到支付成功界面,提示用户支付成功,正在跳转中...

5、当支付失败的时候会触发fail方法,通过判断res.errMsg == 'requestPayment:fail cancel',如果为 真,提示用户您已取消支付,否则提示支付失败和失败的原因。

7)Typescript

7.1 type 和 interface的区别?

相同点:都支持接口扩展 type是通过&(交叉运算符),而interface是通过extends。

不同点:

1、interface只能定义对象类型,type声明还可以定义基础类型、联合类型。

2、interface碰到同名的时候会合并里面的属性,而type碰到同名的会发生冲突报错。

7.2 ts中的泛型

概念:使用泛型可以很好的帮助组件的可复用性。在定义函数、接口或类的时候,可以不预先指定具体的类型,而在使用的时候再进行定义。

在类中的应用:

class AddNumber:number {
    private numArr: number[] = []
    add(num: number) {
        this.numArr.push(num)
    }
    getSum(): number {
        let sum = 0
        return this.numArr.reduce((total, num) => {
            return total + num
        }, sum)
    }
}

上述是不使用泛型时,接下来我们展示使用泛型来进行定义类。

const addFun = new AddNumber()
addFun.add(1)
addFun.add(2)

class AddNumber<T> {
    private numArr: T[] = []
    add(num: T) {
        this.numArr.push(num)
    }
    getSum(): T {
        return this.numArr[0]
    }
}
// 向T赋值为number类型,则在AddNumber类中的所有T都为number类型
const addFun = new AddNumber<number>()
addFun.add(1)
addFun.add(2)

在函数中的应用:  

当我们不使用泛型时:

function identityNumber(value: number): number {
    return value
}
function identityString(value: string): string {
    return value
}
function identityBoolean(value: boolean): boolean {
    return value
}

通过代码可以看出,我们需要对三种返回值,分别声明三种不同的函数。而使用泛型,我们可以直接声明为一种,大大减少了代码量。

function identity <T>(value:T) : T {
    return value
}

8)Nodejs

8.1 nodejs的常见内置模块

http[创建服务器]、path[处理文件路径]、url[处理请求参数]、fs[文件操作]、events[事件总栈]

8.2 平时开发中的使用

schema [存放模型-->通过sequelize.define构建模型]

model [操作数据库的方法-->通过调用create | update | destroy | findAll | fineOne操作数据库]

controllers [业务逻辑模块-->调用model方法]

8.3 koa的概念

Koa最大的特点就是独特的中间件流程控制,是一个典型的洋葱模型,它的核心工作包括两个方面:

  1. 将node原生的req和res封装成为一个context对象。
  2. 基于async/await的中间件洋葱模型机制。

8.4 koa的洋葱模型

Koa的洋葱模型是以next()函数为分割点,先由外到内执行Request的逻辑,然后再由内到外执行Response的逻辑,这里的request的逻辑,我们可以理解为是next之前的内容,response的逻辑是next函数之后的内容。洋葱模型的核心原理主要是借助compose方法。

8.5 如何生成token

1、借助jsonwebtoken这个库,在用户登录成功的时候,调用jwt.sign(传递用户信息+密文+token有效期)生成token,返回给前端。

2、前端拿到token后存储在vuex里面,当调用接口的时候将token携带在请求头中传给后端,然后后端解密token(传递token+之前加密的密文),最后得到用户的角色信息进行权限校验。

9)Webpack

9.1 webpack的核心概念

  • Entry:入口,告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js
  • output:出口,告诉webpack在哪里输出它打包好的代码,默认为./dist
  • Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
  • Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
  • Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
  • Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。

9.2 webpack的构建流程是什么?

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  • 确定入口:根据配置中的 entry 找出所有的入口文件;
  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

9.3 webpack打包原理

把一切都视为模块:不管是 css、JS、Image 还是 html 都可以互相引用,通过定义 entry.js,对所有依赖的文件进行跟踪,将各个模块通过 loader 和 plugins 处理,然后打包在一起。

按需加载:打包过程中 Webpack 通过 Code Splitting 功能将文件分为多个 chunks,还可以将重复的部分单独提取出来作为 commonChunk,从而实现按需加载。把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。

如果像以前开发时一个html文件可能会引用十几个js文件,而且顺序还不能乱,因为它们存在依赖关系,同时对于ES6+等新的语法,less, sass等CSS预处理都不能很好的解决……,此时就需要一个处理这些问题的工具。

9.4 常见的Webpack Loader?

loader: 是一个导出为函数的javascript模块,根据rule匹配文件扩展名,处理文件的转换器。

file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)

url-loader: 与file-loader类似,区别是用户可以设置一个阈值,大于阈值会交给file-loader处理,小于阈值时返回文件base64 形式编码 (处理图片和字体)

image-loader:加载并且压缩图片文件

babel-loader:把 ES6 转换成ES5

sass-loader:将SCSS/SASS代码转换成CSS

eslint-loader:通过 ESLint 检查 JavaScript 代码

css-loader:加载 CSS,支持模块化、压缩、文件导入等特性

style-loader:把 CSS 代码注入到 JavaScript中,通过DOM 操作去加载 CSS

9.5 如何用webpack优化产出代码?

  • 小图片使用base64编码:url-loader

  • 使用import懒加载模块

  • 使用CDN加速:添加publicPath

  • bundlehash:应用缓存

  • 使用splitChunks提取公共组件

  • 使用IgnorePlugin忽略无用的模块

  • 使用production模式:

    • 自动开启代码压缩,使得打包体积更小
    • Vue,React等会自动删除调试代码(比如开发环境的warning警告),体积会比开发时更小
    • 启动tree-shaking,删除无用的代码
  • 使用作用域提升:Scope Hosting

9.6 利用webpack做过哪些配置?

一、element-ui使用rem适配

1、下载postcss-px2rem

2、封装一个rem.js文件,然后根据屏幕宽度,去动态的指定根节点字体大小

3、在vue.config.js里引入postcss-px2rem,然后定义一个变量postcss = px2rem(remUnit: 字体的初始大小16),然后在plugins里面指定postcss

二、图片、js资源使用CDN加速

在build里面的extend中,配置publicPath

10)其他

10.1 项目的开发流程是什么

1、项目背景(可以是老板的想法,也可能是商务谈来的合同)

2、项目流程、规划(产品画原型图)

3、需求评审(工时评估、难点评估)

4、项目设计 (UI出设计图、前后端跟技术总监确认项目架构)

5、开发环节(前后端并行,如果后端接口还未开发,前端就先mock数据或者开发别的项目)

6、提测环节(测试经过一轮以上的测试后,确保没问题了,就跟项目经理确认是否可上线)

7、项目上线

如果是客户的服务器,一般是手动部署:把dist包发给后端去部署到服务器。

如果是公司的服务器,一般是自动部署:通过jenkins自动化构建,提交代码的时候就会自动打包部署。