面试题合集

265 阅读37分钟

面试题种类

概念类、区别类

概念类: 请简单说说事件委托原理

(1)是什么 (2)应用 (3)原理

区别类: localStorage与sessionStorage区别

面试时,注意礼貌,看着面试官,自信一点。

01-前端基础-webpai

1.1-事件委托面试点

  • 1.事件委托:给父元素注册事件,委托给子元素处理,

  • 2.事件委托原理:==事件冒泡==

  • 3.事件委托应用场景 : 给动态新增元素注册委托事件

  • 使用事件委托的好处: 性能高。对后续新增的元素同样有事件绑定效果。

  • 如何按需触发:使用自定义属性。

  • 4.事件委托注意点

    • this : 指向父元素
    • e.target : 指向触发事件的子元素
    • vue也支持事件委托,不过没有必要。现在流行前端框架,基本不怎么使用了。
    • jQuery时代有用,现在的话就用的少了。

利用事件冒泡的原理,把需要绑定到子元素身上的事件,绑定到祖先元素的身上去,其好处:性能高,对后续新增的元素同样有绑定效果,在jQuery时代用的比较多,现在流行前端框架,基本上就用的少了。

1.2-cookie -localStorage与sessionStorage区别

  • 1.相同点

    • 作用一致 : 用于存储数据
    • localStorage和sessionStorage存储大小在5M左右
    • cookie 数据根据不同浏览器限制,大小一般不能超过 4k
  • 2.不同点: 存储方式不同

    • localStorage : 硬盘存储 (永久存储,页面关闭还在,存在硬盘)
    • sessionStorage :内存存储 (临时存储,页面关闭了就消失)
    • cookie 设置的cookie过期时间之前一直有效,与浏览器是否关闭无关
  • 3.localStorage与sessionStorage如何存储引用类型数据(数组和对象)

    • 转json存储

    4 实际应用场景:登录时存储token

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <button class="btn1">存对象</button>
    <button class="btn2">取对象</button>
    <script>
        /* 
        json -> js :   let jsObj = JSON.parse( json格式 )
        js -> json :   let jsonStr = JSON.stringify( js对象 )
        */  
​
        let obj = {
            name:'ikun',
            age:30,
            sex:'男'
        }
        
        document.querySelector('.btn1').onclick = function(){
            //存 : (1)js -> json  (2)存json
            // //(1)js->json
            // let jsonStr = JSON.stringify( obj )
            // //(2)存json
            // localStorage.setItem('user',jsonStr)
​
            //合写一行
            localStorage.setItem('user',JSON.stringify( obj ))
        }
​
        document.querySelector('.btn2').onclick = function(){
            //取: (1)取json  (2)json->js
            // //(1)取json
            // let jsonStr = localStorage.getItem('user')
            // //(2)json->js
            // let jsObj = JSON.parse( jsonStr )
            // 
​
            //合写一行
            let jsObj = JSON.parse( localStorage.getItem('user') )
            console.log( jsObj )
            
        }
    </script>
</body>
</html>

02-前端基础-js高级

1.1-new关键字做了哪些事情

  • 1.创建空对象

  • 2.this指向这个对象

  • 3.对象赋值(执行构造函数)

  • 4.返回实例对象

  • new 构造函数中如果说手动return (1)return 值类型 :无效,还是返回的new创建的这个对象 (2)return 引用类型 :有效,会覆盖new创建的对象

  • 应用: new`用来创建实例对象 比如vue的实例创建。

    1.1.1构造函数,原型对象,实例对象 三者的关系

    • 1.prototype :属于构造函数,指向原型对象
    • 2.—proto— :属于实例对象,指向原型对象
    • 3.constructor: 属于原型对象,指向构造函数

1.2-原型链相关

当访问对象的某一个属性时,会先从自身的属性上去找,当没有找到时就会去他的隐式原型去寻找,如果还没有找到会再去它原型的原型上去寻找,依此类推,形成一个链式结构,我们称为原型链。

  • 1.原型链作用 : 面向对象 继承

  • 2.对象访问原型链规则: 就近原则

    • 先访问自己,自己没有找原型,原型没有找原型的原型,直到原型链终点。 如果还找不到,属性则获取undefined,方法则报错xxx is not defined

实际应用场景:将一个方法或属性挂载在原型上,其他对象也可以访问。 在对axios再次封装时将axios挂载在vue的实例上。

1.3-如何判断this指向

  • this : 谁调用我,我就指向谁
  • 普通函数 函数名() : window
  • 对象方法 对象名.方法名() : 对象
  • 构造函数 new 函数名() : new创建的实例对象
  • 箭头函数的this看外层是否有函数,有的话外层函数的this指向就是内部箭头函数的指向。,没有就是window

1.4-call apply bind区别

  • 共同点:

    • 都可以修改this,第一个参数都是修改的this
    • 都可以利用后续参数传参。
  • 不同点

    • 传参方式不同: call是逐一传参, apply是数组/伪数组传参

      • 函数名.call(修改的this,参数1,参数2....)
      • 函数名.apply(修改的this,数组/伪数组)
      • call和bind可以传递任意的参数。apply只能传递两个元素。
    • 执行机制不同:call和apply会立即执行函数,bind不会立即执行

      • bind会得到一个修改this指向后的新函数

    应用场景:call 判断数据类型。apply: 找出数组中的最大最小值,(Math.max.apply(null,arr))

    我在上班的时候看见他们的机会并不多,我只是看到过这些代码,比如:object.prototypt.tosting.call(), Math.max.apply(null,arr) 求最大值。

1.5-如何判断数据类型

    1. typeof有两种数据类型无法检测: null 、array
    2. instanof 检测原型。(判断两个对象是否属于实例关系。)不能判断基本数据类型。
    1. Object.prototype.toString.call(数据)

1.6-闭包

  • 1.闭包是什么 :

    • 闭包 是 使用其他函数内部变量的 函数 (闭包 = 函数 + 其他函数内部变量)
    • 闭包 = 函数 + 上下文引用
  • 2.闭包作用 : 解决全局变量污染

  • 缺点: 容易造成内层泄露,因为闭包中 的局部变量永远不会被回收

  • 应用场景:闭包随处可见。

  • 手写闭包

  • function fn() {

    var num = 10;

    function fun() {

    console.log(num);

    }

    return fun;

    }

    var f = fn();

    f();

1.7-递归及应用场景

  • 1.递归 : 在函数内部调用自己 (问题相同, 规模不同) 尾递归

  • 优点:结构清晰、可读性强

    缺点:效率低、调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容

    量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。->性能

  • 2.递归应用 :

    • 浅拷贝与深拷贝
    • 遍历dom树
    • 数据扁平化处理

1.8-浅拷贝与深拷贝

  • 1.浅拷贝:拷贝地址, 修改拷贝后的数据原数据也会变化

  • 指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝

    如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

    JavaScript中,存在浅拷贝的现象有:

    • Object.assign
    • Array.prototype.slice(), Array.prototype.concat()
    • 使用拓展运算符实现的复制
  • 2.深拷贝:拷贝数据, 修改拷贝后的数据原数据不会变化

  • 深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

    • 推荐 json : let obj = JSON.parse( JSON.stringify( 对象 ) )
    • 递归
  • 深拷贝的方法有哪些?

1.推荐 json : let obj = JSON.parse( JSON.stringify( 对象 ) )

2.Object.assign()拷贝

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

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

4.lodash.cloneDeep()实现深拷贝

1.9-数组常用迭代方法

1 连接 arr.join()

2 reverse() 将数组中各元素颠倒顺序

3 pop() 删除数组中最后一个元素,返回删除的那个值,并将长度减 1。

4 shift() 删除数组中第一个元素,返回删除的那个值,并将长度减 1。

5 unshift() 往数组前面添加一个或多个数组元素,长度要改变

6 push() 往数组结尾添加一个或多个数组元素,长度要改变

7 splice( ) 插入、删除或替换数组的元素

8 concat( ) 连接数组

9 sort( ) 对数组元素进行排序

10 slice( ) 返回数组的一部分

11 forEach 遍历所有元素

12 every 判断所有元素是否都符合条件

13 map 指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。

14 filter 过滤符合条件的元素

15 some():判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。

16 findIndex方法,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

17 Array.Includes 用于判断数组中是否有此元素

18 Array.reduce()接受两个参数:一个是对数组每个元素执行的回调方法,一个是初始值。

19 Array.from方法用于将伪数组转为真正的数组

20 数组去重indexOf、Set、include

1.10-for in与for of区别

(1)功能不同

    for - in 遍历下标和元素
    for-of 遍历元素
(2)原型不同
    for-in 可以遍历原型中的属性
    for-of不可以遍历原型中的属性
(3)数据类型不同
    for-in 可以遍历 数组+对象
    for-of 遍历对象时需要和object.key()配合使用。
总结应用:  如果想要下标和元素就用  for-in   只想要元素就用for-of

1.10-防抖和节流

1防抖:单位时间内,频繁触发事件,只会触发最后一次

2节流: 单位时间内,频繁触发事件,只会触发一次

3 作用:相用点: 减少触发的频率,提高代码的性能

3.1.函数防抖流程 :(立刻执行,非立刻执行两种。)

3.1 声明全局变量存储定时器ID 3.2 每一次触发事件, 先清除上一次定时器。 然后将事件处理代码放入本次定时器中 3.3开启定时器

​​

3.2.函数节流流程 : 3.1 声明全局变量存储上一次触发交互时间 3.2 每一次触发事件, 获取当前时间 - 上一次时间。判断是否超过节流间隔 3.3 如果 超过节流时间,则执行事件处理代码。 并且存储本次触发时间。

实际应用场景:防抖:输入框输入事件 input事件。

节流:滚动条事件scroll事件 鼠标移动mousemove事件

1.11浏览器中的事件循环

事件循环(Event Loop)是js实现异步的一种方法,也是js的执行机制

  • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
  • 当指定的事情完成时,Event Table会将这个函数移入消息队列
  • 主线程内的任务执行完毕为空,会去消息队列读取对应的函数,进入主线程执行。
  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。

web worker

1.12 async await 是什么?它有哪些作用?

async await 是es7里面的新语法、它的作用就是 async 用于申明一个 function 是异步的,而 await 用

于等待一个异步方法执行完成。它可以很好的替代promise 中的then ,async/await 最大的优势就是我们可以用同步的思路来写异步的业务逻辑

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇

到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

缺点:

代码不容易理解。

await 表达式会阻塞运行,甚至可以直接阻塞循环,不恰当使用会影响代码的性能

应用场景: 在发送异步请求,拿数据时会用。

  • 概念
  1. Promise Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大,简单地说,Promise好比容器,里面存放着一些未来才会执行完毕(异步)的事件的结果,而这些结果一旦生成是无法改变的

  2. async await async await也是异步编程的一种解决方案,他遵循的是Generator 函数的语法糖,他拥有内置执行器,不需要额外的调用直接会自动执行并输出结果,它返回的是一个Promise对象

    两者的区别
    1. Promise的出现解决了传统callback函数导致的“回调地狱”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。而async await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。
    2. async await与Promise一样,是非阻塞的。
    3. async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。
    4. Promise 中不能自定义使用 try/catch 进行错误捕获,但是在 Async/await 中可以像处理同步代码处理错误

1.13、常见的继承有哪些?

一、原型链继承

特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新

实例不会继承父类实例的属性!

缺点:1、新实例无法向父类构造函数传参。

2、继承单一。

3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属

性,另一个实例的原 型属性也会被修改!)

二、借用构造函数继承

function fn() {

var num = 10;

function fun() {

console.log(num);

}

return fun;

}

var f = fn();

f();

1

2

3

4

5

6

7

8

9重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复

制))

特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。

2、解决了原型链继承缺点1、2、3。

3、可以继承多个构造函数属性(call多个)。

4、在子实例中可向父实例传参。

缺点:1、只能继承父类构造函数的属性。

2、无法实现构造函数的复用。(每次用每次都要重新调用)

3、每个新实例都有父类构造函数的副本,臃肿。

三、组合继承(组合原型链继承和借用构造函数继承)(常用)

重点:结合了两种模式的优点,传参和复用

特点:1、可以继承父类原型上的属性,可以传参,可复用。

2、每个新实例引入的构造函数属性是私有的。

缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函

数。

四、原型式继承

重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的

实例或对象。object.create()就是这个原理。

特点:类似于复制一个对象,用函数来包装。

缺点:1、所有实例都会继承原型上的属性。

2、无法实现复用。(新实例属性都是后面添加的)

五、* class*类实现继承

通过extends 和super 实现继承

六、寄生式继承

重点:就是给原型式继承外面套了个壳子。

优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成

了创建的新对象。

缺点:没用到原型,无法复用。

1.14 平时都是用什么实现跨域的?

说起跨域,我们不得不提的是同源 什么是同源呢? 同源= 协议 +域名 +端口 , 同源策略是指,若页面的源和页面运行过程中加载的源不一致时,出于安全考虑,浏览器会对跨域的资源访问进行一些限制** 当发送aiax请求时,只要其中任何一个不相同,我们都称之为跨域

解决:

1 jsonp: 利用 script 标签没有跨域限制的漏洞,设置src

2 CORS:跨域资源共享 **CORS 需要浏览器和后端同时支持。

浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域

3 nginx反向代理

实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。

使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

4 .proxy跨域配置

利用node中间件proxy配置跨域(此处只介绍vite中的代理配置)
node proxy跨域原理图

vite.config.js中
proxy: {
  1.如发送请求/api/xxx,此时请求拦/api
  '/api': {
    2.路径转发,此时请求地址变为http://localhost:5001/api/xxxx
    target: 'http://localhost:5001',
    changeOrigin: true,//请求改变源,此时nginx可以获取到真实的请求ip
    3.路径重写,此时请求变成了http://localhost:5001/xxxx,
    path.replace(/^/api/, ‘’)-->将请求地址中的api去除了
    rewrite: (path) => path.replace(/^/api/, ‘’)
  }
}

1.15* 、谈谈你平时都用了哪些方法进行性能优化?*

减少http请求次数、打包压缩上线代码、使用懒加载、使用雪碧图、动态渲染组件、CDN加载包。尽量减少Dom元素的重绘和回流

1.16 js的执行机制是怎么样的?

js是一个单线程、异步、非阻塞I/O模型、 event loop事件循环的执行机制

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。

异步 任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,

某个异步任务可以执行了,该任务才会进入主线程执行。

1.17 、数据类型的判断有哪些方法?他们的优缺点及区别是什么?

1.18 promise* 是什么?它有哪些作用?*

Promise 是异步编程的一种解决方案.(改变异步代码结果处理的顺序)是es6新增的函数,一般作为一个构造函数去使用,需要new一下,来创建一个promise实例,它有三种状态分别是:pending(进行中),fufilled(已成功),rejected(以失败) 成功会触发then,失败会触发 cath; 还有一个finally是永远都会被触发。

我们会用它去解决回调地狱的问题,也就是异步深层嵌套的问题,,但使用promise并不能简化代码,所以在工作中我一般都会配合 async ,await 来使用。

promise.race() 接收多个promise实例,可以的到最先处理完毕的结果。

promise.all() 接收多个实例参数,都成功会触发then,有一个失败就会触发catch

promise.any() 接收多个实例参数,可以的到最先处理成功的结果,都失败才会触发catch.

1.19 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生 了什么?

1 DNS域名解析:将域名解析为IP地址 2 TCP三次握手:可靠的传输协议 2.1 浏览器->服务器 :在吗?能听到我说话吗?(浏览器发送 ok) 2.2 服务器->浏览器 :我在,听到了 你能听到我说话吗?(服务器接收ok 发送 ok) 2.1 浏览器->服务器 :我也听到你说话了,咱们开始吧(浏览器发送 ok)

3 发送http请求,处理,响应 ajax发送请求 服务器处理 服务器响应html格式文件

4 浏览器解析渲染HTML文件 (1)解析HTML 得到dom树 (2)解析CSS 得到样式树 (3)渲染树 = dom树+样式树 (4)渲染引擎 开始绘制渲染树,并呈现页面 */

1.20 重绘和回流

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

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

什么情况下会导致回流?

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

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

  • clientWidth、clientHeight、clientTop、clientLeft
  • offsetWidth、offsetHeight、offsetTop、offsetLeft
  • scrollWidth、scrollHeight、scrollTop、scrollLeft
  • scrollIntoView()、scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

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

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

1.21 BFC的理解

块级格式化上下文,是一种特性,他拥有自己的一套渲染规则,他决定了其子元素将如何布局,以及和其他元素的相互作用关系。

作用:

1,可以包含内部浮动的元素,

2,可以排除外部浮动带来的影响,

3,阻止外边距重叠,(处于同一BFC中,中间没有具有高度的元素隔开的化,外边距会有重叠。)

4,解决margin塌陷问题

触发BFC特性:

1.根元素(html)

2 浮动元素(元素的flot不是none)

3绝对定位的元素(元素的position为absolute或fixed)

4,行内块元素(元素的display为inline-block)

5 overflow不等于visible

6 display值为flow-root的元素 (没有副作用,常用)

1.22 em和rem的区别

em相对于元素自身字体大小的一个元素,而rem相对于根元素(rem)字体大小的一个单位。

1.23 rem适配的原理

利用媒体查询或 js动态的检测/获取设备的宽度,不同宽度下设置相应的根元素字体大小,当设备宽度变化,根元素字体大小跟着变,那么所有使用rem做适配的元素自然也跟着变。

适配:不同设备宽度不同,显示的内容大小不同。

1.24 如何实现一个盒子水平/垂直居中

1.利用flex布局

display:flex

justify-content:center, 主轴居中

align-items:center 侧轴居中

2 父元素设置相对定位,子元素设置绝对定位

3:在有时不知道盒子自身宽高的情况下使用transform:translate(-50%,-50%)进行位移。

1.24,函数传参,传递简单数据类型和复杂数据类型有怎样的差异。

1.25箭头函数和普通函数的差异

箭头函数是es6新增的特性,用来简化普通函数的写法,规避普通函数this指向的痛点。

1.没有this (不能作为构造函数使用,不能通过 call apply bind修改this指向,不能用作generator函数)

2可以简写,

3内部没有arguments 可以使用'...'拿到所有实参的集合数组

1.26如何并发请求

promise.all()

1.27图片懒加载

常见的性能优化的手段,他的核心的思路。图片不在可视区时不设置src 在进入可视区时再去设置src ,其主要的难度在于,检测元素是否在可视区内,在以前时需要通过一系列的计算来判断,现在的话,浏览器提供了一个api: intersectonobserver来监听元素是否可见,在vue技术栈中开发中在vueuse中有一个useintersectonobserver 这个api更好的来帮助我们判断元素是否可见。

  • 先将img标签的src链接设为同一张图片(默认图片),当js监听到该图片进入可视窗口时,再将实际地址应用。
  • 判断元素是否可见浏览器有一个api: intersectonobserver来监听元素是否可见,在开发中在vueuse中有一个useintersectonobserver 这个api更好的来帮助我们判断元素是否可见。

2021年我的前端面试准备 - 掘金 (juejin.cn)

Vuex面试题汇总 - 掘金 (juejin.cn)

1.28.后端给十万条数据怎么处理?

  1. 采用懒加载+分页(前端维护懒加载的数据分发和分页)

    懒加载和分页方式一般用于做长列表优化, 类似于表格的分页功能, 具体思路就是用户每次只加载能看见的数据, 当滚动到底部时再去加载下一页的数据.

  2. 使用虚拟滚动技术(目前react的antd4.0已支持虚拟滚动的select长列表)

    虚拟滚动技术也可以用来优化长列表, 其核心思路就是每次只渲染可视区域的列表数,当滚动后动态的追加元素并通过顶部padding来撑起整个滚动内容

1.29.文件上传,断点上传?

大文件上传
  • 将大文件转换成二进制流的格式
  • 利用流可以切割的属性,将二进制流切割成多份
  • 组装和分割块同等数量的请求块,并行或串行的形式发出请求
  • 待我们监听到所有请求都成功发出去以后,再给服务端发出一个合并的信号
断点续传
  • 为每一个文件切割块添加不同的标识
  • 当上传成功的之后,记录上传成功的标识
  • 当我们暂停或者发送失败后,可以重新发送没有上传成功的切割文件

1.30.es6新增的那些特性?

  1. 新增let和const

1,相同点,都是用来声明变量的

2不同点 :

2.1var没有块级作用域,但有变量提示效果 let const 有块级作用域,没有变量提示的效果 2.2 const声明后必须赋值,且赋值是一个常量 3.3 let const不允许重复声明,var可以重复声明

2:新增了箭头函数(本身是没有this的)。简化定义函数的写法,

3.新增了promise解决回调地狱的问题。

4.新增了模块化 import export 实现导入导出。

5新增了解构赋值。展开运算符。

  • 6 Map 和 Set:

  • Map对象用于保存键值对,任何值JavaScript支持的值都可以作为一个键或者一个值。这听起来和对象差不多啊?其实它们还是有区别的:

    a) object的键只能是字符串或ES6的symbol值,而Map可以是任何值。

    b) Map对象有一个size属性,存储了键值对的个数,而object对象没有类似属性。

Map构造函数接收一个二维数组来创建一个Map对象。数组元素的第0位表示Map对象的key,第1位表示Map对象的value。

  Map对象使用set方法来新增数据,set方法接收两个参数,第一个表示key,第二个表示value。使用get方法获取数据,参数是对象的key。

  Map对象使用delete方法来删除数据,接收一个参数,表示需要被删除的key。

  Map对象使用has方法检测是否已经具有某个属性,返回boolean值。

  Set对象和Map对象类似,但它是用来存储一组唯一值的,而不是键值对。类似数组,但它的每个元素都是唯一的。

03-服务器课程-ajax

 get与post的区别

    *(1)传参方式不同

            get: 直接在url后面拼接

            post: 在请求体中发送

      (2)传参速度不同

            get: 传输速度快

            post: 传输速度慢

      (3)数据大小不同

            get: 有大小的限制,不同浏览器,大小限制不同

            post: 没有大小的限制

           一般文件的上传都是post

      (4)安全性不同

            get:get的安全性低。

            post: post的安全性高。

           登录注册一般都是post

04-服务器课程-nodejs

常见的git操作

git branch 查看本地所有分支

git status 查看当前状态

git commit 提交

git branch -a 查看所有的分支

git branch -r 查看远程所有分支

git commit -am "init" 提交并且加注释

git remote add origin git@192.168.1.119:ndshow

git push origin master 将文件给推到服务器上

git remote show origin 显示远程库origin里的资源

git push origin master:develop

git push origin master:hb-dev 将本地库与服务器上的库进行关联

git checkout --track origin/dev 切换到远程dev分支

git branch -D master develop 删除本地库develop

git checkout -b dev 建立一个新的本地分支dev

git merge origin/dev 将分支dev与当前分支进行合并

git checkout dev 切换到本地dev分支

git remote show 查看远程库

git add . git rm 文件名(包括路径) 从git中删除指定文件

git clone git://github.com/schacon/grit.git 从服务器上将代码给拉下来

git config --list 看所有用户

git ls-files 看已经被提交的

git rm [file name] 删除一个文件

git commit -a 提交当前repos的所有的改变

git add [file name] 添加一个文件到git index

git commit -v 当你用-v参数的时候可以看commit的差异

git commit -m "This is the message describing the commit" 添加commit信息 git commit -a -a是代表add,把所有的change加到git index里然后再commit git commit -a -v 一般提交命令 git log 看你commit的日志 git diff 查看尚未暂存的更新 git rm a.a 移除文件(从暂存区和工作区中删除) git rm --cached a.a 移除文件(只从暂存区中删除) git commit -m "remove" 移除文件(从Git中删除) git rm -f a.a 强行移除修改后文件(从暂存区和工作区中删除) git diff --cached 或 $ git diff --staged 查看尚未提交的更新 git stash push 将文件给push到一个临时空间中 git stash pop 将文件从临时空间pop下来

05-框架: Vue

1.1-v-if和v-show异同点

v-show和v-if的区别? 分别说明其使用场景?

共同点: v-if和v-show都是控制元素是否可见的。

不同点:原理,性能,和应用场景上有所不同。

原理:

v-show是采用的display:none (样式上对元素进行显示隐藏)

v-if采用的是惰性加载 (他会控制元素是否被创建或销毁。)

性能: v-if比v-show更加消耗性能。

实际应用场景:当需要频繁切换显示隐藏使用v-show (tab栏的切换)

在运行时条件很少改变,则使用 v-if 较好 (在做权限的控制中,控制页面级别按钮是否可见)

为什么避免v-for和v-if在一起使用

效率低:有效率更高的做法,用计算属性过滤一下。

vue2和3中的表现不同,现在的话不会这样写。一定要写的话,会

通过计算属性,先计算出需要循环的元素。

还有一种就是把v-if先放在templte中进行包裹,再进行v-for循环展示。.

1.2-vue生命周期勾子有哪些

总: Vue 实例从创建到销毁的过程,就是生命周期。初始化=>挂载=>更新=>销毁

1,vue2的生命周期:四个阶段八个钩子函数

初始化=>挂载=>更新=>销毁

beforeCreate === created ===beforeMount ===mounted===beforeUpdate===updated===beforeDestroy===destroyed

其他钩子:activated === 在 keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。

deactivated === 在 keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。

  1. 常用的有三个: created(发送ajax请求),mounted(获取DOM元素,用echer画图时,我们需要操作Dom,需要用到。),beforeDestroy(清空定时器)
  2. vue3中的钩子函数和vue2中的有所不同。(setup代替了beforeCreate 和created ,其他钩子在名称前都加了on)
可能衍生的问题vue在第一次加载时会执行哪些钩子

在页面第一次加载时会执行: beforeCreate =>created=>beforeMount=>mounted 这几个钩子函数。

父子组件的生命周期钩子函数执行顺序:

Vue 实例从创建到销毁的过程,就是生命周期。初始化=>挂载=>更新=>销毁

1**)beforeCreate (vue实例刚刚创建) vue 实例刚刚在内存中创建,此时 data 和 methods 这些都没初始化好。 比beforeCreate 更早的的是setup

2* )created*(访问到data中的数据 发送ajax请求) vue 实例在内存中已经创建好了,data 和 methods 也能够获取到了,但是模板还没编译。

可以访问到data中的数据 发送异步请求

3* )beforeMount*()

在挂载开始之前被调用:创建 虚拟DOM 相关的 render 函数首次被调用。 完成了模板的编译,但是还没挂载到页面上。 

4* )mounted*(挂载到真实Dom上)(用echer画图时,我们需要操作Dom,需要用到。用echer画图时,我们需要操作Dom,需要用到。)

把虚拟DOM 挂载到真实的DOM上, 在Vue中可以获取DOM元素对象  模板编译完成,挂载完成,页面也可以显示。

5* )beforeUpdate*

数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

6* )updated*

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

7* )activated*

keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。

8* )deactivated*

keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。

9* )beforeDestroy* (清空定时器。)

实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

10* )destroyed*

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

11* )errorCaptured(2.5.0+ 新增)*

当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

常用的有三个: created,mounted,beforeDestroy

Vue2--------------vue3

beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated
errorCaptured -> onErrorCaptured

1.3-vue在第一次加载时会执行哪些钩子

在页面第一次加载时会执行: beforeCreate =>created=>beforeMount=>mounted 这几个钩子函数。

1.4 created和mouted的区别

1.首先,created()mounted() 都可以访问原型上的 dataprops

2 在created()中非常适合调用 API,发送异步请求。而mounted()` 非常适合在 DOM 元素完全加载后执行任何操作。

实际应用: 在created()钩子函数中 发送异步请求, 而在mounted()中去获取更新后的DOM

在created中对chart.js做图时,进行一些初始化配置时,去操作html的dom节点,找不到相关的元素。这时候使用mounted()

1.5 :v-model双向数据绑定的原理

在vue2中

1其本质是语法糖。v-model即可以作用于表单元素,又可作用于自定义组件,无论是哪一种情况(vue2, vue3),它都是一个语法糖,最终会生成一个属性和一个事件

原理: 在input框里面通过v-bind动态绑定一个value,然后在input框里面通过@input方法去动态获取input输入的值,然后重新给变量赋值就可以了。

在vue3中:

modelValue属性和onUpdate:modelValue事件。

  1. 给子组件传递一个属性:modelValue,

2。监听子组件上的事件update:modelValue,在回调函数中,将从子组件回传的值保存

实际应用场景:收集用户输入的数据。以及父子组件传值中都有用到。

1.6:vue响应式的原理:

1.vue主要是通过:数据劫持 + 依赖收集(发布者-订阅者模式)的方式来实现的。

2.Vue2.x是借助Object.defineProperty()实现的,而Vue3.x是借助Proxy实现的,

3 vue2. 原理:3.1通过Object.defineProperty为对象添加属性,可以设置对象属性的gettersetter函 数。(遍历生成对应的setter,getter函数)

3.2 在获取属性时都会执行getter函数,在这个函数中我们会把调用此属性的依赖收集到一个集合中 ;

3.3 在修改属性时,会触发这里定义的setter函数,在setter函数中会去通知集合中的依赖更新,做到数据变更驱动视图变更。

4 vue3.中的响应式与2.x的核心思想一致,只不过数据的劫持使用Proxy(一次性的添加getter和setter函数)而不是Object.defineProperty,Proxy相比Object.defineProperty在处理数组和新增属性的响应式处理上更加方便。

1.7 组件中的data为什么要定义成一个函数而不是一个对象?

每个组件都是 Vue 的实例。组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一 个会影响其他 ,。而如果data是一个函数是,他得到的是一个返回后的新函数,改变其中一个时他不会影响到其他。

1.8 vue中computed 和watch的区别是什么?

computed(计算属性) :

computed也是一个特殊的watch

1 支持缓存,只有依赖数据发生改变,才会重新进行计算。

2 不支持异步,当computed内有异步操作时无效,无法[监听]数据的变化

4 在使用上:如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed 5 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法

watch( 侦听属性)

1 不支持缓存,数据变,直接会触发相应的操作; 2 watch支持异步; 3 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值; 4 当一个属性发生变化时,需要执行对应的操作;一对多;

5 watch监听对象时需要配合deep:true属性使用

6 immediate:true 页面首次加载的时候做一次监听

注意

不要在 computed 或 watch 中,去修改所依赖的数据的值,尤其是 computed;如果这样做,可能导致一个无线循环的触发。

应用场景: 实际得到的数据不能直接放到页面中展示,而是需要进行一些操作处理,就使用computed。

  • watch 适用场景:一个数据影响多个数据;当需要在数据变化时执行异步或开销较大的操作时 (计数器)(监听路由的变化)
  • computed适用场景:一个数据受多个数据影响;(购物总价的计算)

实际得到的数据不能直接放到页面中展示,而是需要进行一些操作处理,就使用computed。

当需要在数据变化时执行异步或开销较大的操作时,就使用watch。

1.9 什么是Pinia以及它的作用?

pinia是什么?

pinia是用于vue的状态管理库,类似于vuex,是vue的另一种状态管理工具

与vuex相比

与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。

  • mutations 不再存在。
  • 无需创建自定义复杂包装器来支持 TypeScript,所有内容都是类型化的,并且 API 的设计方式尽可能利用 TS 类型推断。
  • 不再需要注入、导入函数、调用函数、享受自动完成功能!
  • 无需动态添加 Store,默认情况下它们都是动态的
  • 不再有 modules 的嵌套结构

安装pinia(仅限于vue3):

npm install pinia`或者 `yarn add pinia

使用

  1. 在src目录下新建一个stroe文件夹,在文件夹中新建一个index.ts
  2. 通过import将下载好的pinia引入到index.ts中并导出
import { createPinia, defineStore } from 'pinia'
 
export const Pinia = createPinia()
 
export default defineStore('admin', {
//这里的state与vue2中用来存放初始化变量的data的写法相似,需要return
 state: () => {
        return {
            count: 100,
 
        }
    },
 
 getters: {
        count: state => state.count
      },
//Actions 相当于组件中的 methods。 它们可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑:
  actions: {
       
        }
       
    },
 
})

在main.js中进行注册:

import { createApp } from 'vue'
import App from './App.vue'
import { Pinia } from './store/index'
 
 
 
const app = createApp(App)
 
 
app.use(Pinia)
app.mount('#app')

了解更多pinia中文官网链接

1.10 hash模式和history模式的区别?

相同点:这两种模式都可以进行路由的跳转。

不同之处有三点。

一是原理不同。

hash模式的实现原理是通过监听hashChange事件来实现的。

history模式是通过调用 history.pushState方法(或者replaceState) 并且 监听popstate事件来实现的。

history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听popstate事件是为了响应浏览器的前进后退功能。

二是表现不同。hash模式会在地址栏中有#号,而history模式没有;同时由于history模式的实现原理用到H5的新特性,所以它对浏览器的兼容性有要求(IE >= 10)。

三是history模式开发的SPA项目,需要服务器端做额外的配置,否则会出现刷新白屏(链接分享失效)。原因是页面刷新时,浏览器会向服务器真的发出对这个地址的请求,而这个文件资源又不存在,所以就报404。处理方式就由后端做一个保底映射:所有的请求全部拦截到index.html上。

1.11 Vue中的$nextTick有什么作用?

立即能够获取更新后的dom元素,本质是一种优化策略。

vue在更新Dom时是异步执行的,当数据发生变化时,vue会开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新,而$nextTick就应运而生了,我们可以使用它,来立即获取更新后的DOM元素。

原理:

  1. 把回调函数放入callbacks(异步操作队列)等待执行
  2. 将执行函数放到微任务或者宏任务中
  3. 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调

应用:

  1. created中获取DOM的操作需要使用它

1.12 什么是虚拟DOM?

(1)vue在执行时会将模板(template)通过 vue-loader编译为渲染函数(render)(只会做一次)

(2)渲染函数会根据当前的数据data生成虚拟DOM树

(3)虚拟Dom树会和上次的虚拟Dom树通过diff算法做对比

(4)局部更新真实Dom,在上一轮真实Dom的基础上打补丁(patch)

虚拟Dom就是一个(树状)js对象。有跨平台的能力,体积小,性能提升的优点。

虚拟dom(virtual dom ===> vdom)

虚拟DOM是由js实现的避免DOM树频繁更新,通过js的对象模拟DOM中的节点,然后通过特定的render方法将它渲染成真实的节点,数据更新时,渲染得到新的 Virtual DOM,与上一次得到的 Virtual DOM 进行 diff,得到所有需要在 DOM 上进行的变更,然后在 patch 过程中应用到 DOM 上实现UI的同步更新。

diff算法:

diff算法特点:(diff算法就是进行一个虚拟节点的·对比,返回一个patch对象,存储两个节点不同的地方,最后用patch的记录去局部更新Dom)调用patch函数比较新旧节点,一边比较一边给真实dom打补丁。

同级比较(四个指针,头对头,尾对尾,交叉对比,没有找到就是新增,找到就是复用) ,

深度优先(递归)

1.13 vue3新特性

  1. 数据响应式原理重新实现 (ES6 proxy 替代了 ES5 的 Object.defineProperty) 解决了: 例如数组的更新检测等bug, 大大优化了响应式监听的性能 (原来检测对象属性的变化, 需要一个个对属性递归监听) proxy 可以直接对整个对象劫持
  2. 虚拟DOM - 新算法 (更快 更小)
  3. 提供了composition api, 可以更好的逻辑复用
  4. 模板可以有多个根元素
  5. 源码用 typescript 重写, 有更好的类型推导 (类型检测更为严格, 更稳定)

1.14 setup 函数

setup 函数的特点:

composition api的使用, 需要配置一个setup 函数

  1. setup 函数是一个新的组件选项, 作为组件中 compositionAPI 的起点
  2. 从生命周期角度来看, setup 会在 beforeCreate 钩子函数之前执行
  3. setup 中不能使用 this, this 指向 undefined
  4. 在模版中需要使用的数据和函数,需要在 setup 返回。

1.15 组件传值方式:

1,常用父子传值 props $emit / v-on slot插槽 2,不常用父子传值 $parent / $children ref / $refs 3,语法糖传值 v-model .sync 4,跨级通信 eventBus Vuex provide / inject $attrs / $listeners 5,访问根组件 $root

1.16说一下SPA单页面有什么优缺点?

优点:
​
1.体验好,不刷新,减少 请求  数据ajax异步获取 页面流程;
​
2.前后端分离
​
3.减轻服务端压力
​
4.共用一套后端程序代码,适配多端
​
缺点:
​
1.首屏加载过慢;
​
2.SEO 不利于搜索引擎抓取
​
​

1.17 路由传参

1、通过params方式传参

通过$route.push的path携带参数方式 (路由配置中指定参数)

这种方式参数是以/id跟在url后,刷新页面后参数不会丢失。

通过$route.push的params传参 (路由配置中未指定参数)

这种方式的传参,必须使用name进行跳转,未在路由配置:id,url后不会显示id,刷新页面后 参数会丢失。

2、通过query方式传参

这种方式的参数以?id跟在url后,类似get传参,并且,query必须使用path进行传参。刷新页面后参数不会丢失。

1.18 key的作用

1更加高效的更新虚拟DOM。

2 key是每一个虚拟Dom的唯一id,也是diff算法的一种优化策略,可以根据key更准确,更快的找到对应的虚拟Dom的节点。

讲加了key和不加key的区别。

应用场景:v-for循环。

1.19 vue2的缺点:

1.深度监听需要一次性递归。

2无法监听对象新增|删除的属性。

3无法监听数组的元素操作。

4 在vue3中使用了proxy代替了Object.defineProperty解决了这些问题。

1.20你会在vue的哪个生命周期钩子里面发请求,为什么

首先来说,发请求的时机肯定是越早越好的,但是还有一点,有时候请求前需要依赖data里面的数据,或调用methods里面的方法,而data和methods都是需要实例创建完毕后(created)才具有的,所以一般在created里面发请求。

不过有时候在这个请求需要依赖DOM相关操作的话,我会选择在mounted中进行。

1.20路由守卫的理解

1、全局前置守卫—— router.beforeEach

包含三个参数:

(1)to(必填) :即将要进入的目标————通俗来说就是去哪儿

(2)form(必填) :当前导航正要离开的路由————通俗来说就是来自哪

(3)next(可选) : 钩子函数,里面定义参数,确认下一步路由要做什么 next('/')或者 next({ path: '/' }):跳转到一个不同的地址。

一般应用在用户未能验证身份时重定向到 /login

2、全局解析守卫————router.beforeResolve

这和 router.beforeEach 类似,因为它在 每次导航时都会触发,但是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用

3、全局后置钩子————router.afterEach

和守卫不同的是,后置钩子不会接受 next函数也不会改变导航本身:

router.afterEach((to, from) => { // 在全局内置守卫中使用功能包(特效),可在后置钩子中进行终止

})

4、路由独享的守卫————beforeEnter

你可以直接在路由配置上定义,但是它只在进入路由时触发,不会在 paramsqueryhash 改变时触发。

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // reject the navigation
      return false
    },
  },
]
复制代码

5、组件内的守卫

  • beforeRouteEnter ---进入前
  • beforeRouteUpdate --- 路由变化时
  • beforeRouteLeave --- 离开后

完整的导航解析流程#

  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 的回调函数,创建好的组件实例会作为回调函数的参数传入

1.21.单页面数据优化,

单页面:

SPA首屏优化方式
  • 减小入口文件积

    常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包 路由,使得入口文件变小,加载速度大大增加。

  • 静态资源本地缓存

    前端合理利用localStorage

  • UI框架按需加载

    不直接引用整个UI库,按需引入

  • 图片资源的压缩

    对于所有的图片资源,我们可以进行适当的压缩

    对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以 减轻http请求压力。

  • 组件重复打包

  • 开启GZip压缩

    减少首屏渲染时间的方法有很多,总的来讲可以分成两大部分 :资源加载优化 和 页面渲染优化

1.22.有没有使用哈希路由

hash模式

1.url路径会出现#字符。

  1. hash值不包括在http请求中,他是交由前端路由处理的.所以改变hash值时,它不会刷新页面,也不会发送请求。 3. hash值的改变会触发hashchange事件。

1.23.爆400 怎么弄

HTTP请求状态码400,说明这个请求是无效的,并没有进入后台服务器(控制器)里。

原因一:请求参数个数不对。,

原因二:请求参数的类型不对

原因三:Get请求的url长度超过浏览器或web服务器限制。

解决办法: 对照参数名称 ,个数,类型 等保证一致。

1.24.vuex 是怎么理解的

Vuex 是一个专为 Vue.js 应用程序开发的状态管理工具。它采用集中式存储管理应用的所有组件的状态,而更改状态的唯一方法是提交mutation

当项目遇到以下两种场景时

  • 多个组件依赖于同一状态时。
  • 来自不同组件的行为需要变更同一状态。

5个核心属性

state、getters、mutations、actions、modules 。

Vuex中状态是对象时,使用时要注意点:

因为对象是引用类型,复制后改变属性还是会影响原始数据,这样会改变state里面的状态,是不允许,所以先用深度克隆复制对象,再修改。

Vuex中action和mutation有什么区别?

有用过Vuex模块吗,为什么要使用,怎么使用。

有,因为使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。所以将 store 分割成模块(module)。每个模块拥有自己的 state、mutations、actions、getters,甚至是嵌套子模块,从上至下进行同样方式的分割。

在module文件新建moduleA.js和moduleB.js文件。在文件中写入

const state={ //... } const getters={ //... } const mutations={ //... } const actions={ //... } export default{ state, getters, mutations, actions }

然后再index.js引入模块

import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); import moduleA from './module/moduleA' import moduleB from './module/moduleB' const store = new Vuex.Store({ modules:{ moduleA, moduleB } }) export default store

Vuex面试题汇总 - 掘金 (juejin.cn)

1.25.vuex 持久化怎么解决

1.手动利用HTML5的本地存储

方法

  • vuex的state在localStorage或sessionStorage或其它存储方式中取值
  • 在mutations,定义的方法里对vuex的状态操作的同时对存储也做对应的操作。

2.利用vuex-persistedstate插件

Vuex持久化插件-解决刷新数据消失的问题 - 掘金 (juejin.cn)

1.26插槽你是怎么理解的

插槽,其实就相当于占位符。它在组件中给你的HTML模板占了一个位置,让你来传入一些东西。插槽又分为 匿名插槽、具名插槽、作用域插槽。

1.27.插槽分几种

匿名插槽 我们也可以叫它单个插槽或者默认插槽。和具名插槽相对,它是不需要设置 name 属性的,它隐藏的name属性为default ,也可以不写就是默认的意思啦

具名插槽 顾名思义就是slot 是带有name的 ,定义: 或者使用简单缩写的定义 #header 使用:要用一个 template标签包裹

作用域插槽 就是用来传递数据的插槽 。如果希望在父组件中的插槽中使用到子组件中对应插槽的数据源,可以使用作用域插槽(子组件 slot 中用到的数组中可以传给父组件来使用)

1.28.自定义指令 有没有用到过 具体说一说你定义过的

Vue自定义指令和组件一样存在着全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive( id, [definition] ) 方式注册全局指令,第一个参数为自定义指令名称(指令名称不需要加 v- 前缀,默认是自动加上前缀的,使用指令的时候一定要加上前缀),第二个参数可以是对象数据,也可以是一个指令函数。

​​

定义过自定义指令有v-lazy其就是一个图片懒加载的功能,在开始时不设置src属性.当图片可见时(IntersectionObserver判断元素可见)去设置src加载图片。

20常用的修饰符有哪些

  • 1.29. 常用的修饰符有哪些

    vue中修饰符分为以下五种:

    • 表单修饰符
    • 事件修饰符
    • 鼠标按键修饰符
    • 键值修饰符
    • v-bind修饰符

    表单修饰符

    在我们填写表单的时候用得最多的是input标签,指令用得最多的是v-model

    关于表单的修饰符有如下:

    • lazy:在我们填完信息,光标离开标签的时候,才会将值赋予给value,也就是在change事件之后再进行信息同步
    • trim:自动过滤用户输入的首空格字符,而中间的空格不会过滤
    • number:自动将用户的输入值转为数值类型,但如果这个值无法被parseFloat解析,则会返回原来的值

    事件修饰符

    事件修饰符是对事件捕获以及目标进行了处理,有如下修饰符:

    • stop:阻止了事件冒泡,相当于调用了event.stopPropagation方法
    • prevent:阻止了事件的默认行为,相当于调用了event.preventDefault方法
    • self:只当在 event.target 是当前元素自身时触发处理函数
    • once:绑定了事件以后只能触发一次,第二次就不会触发
    • capture:使事件触发从包含这个元素的顶层开始往下触发
    • passive:在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符
    • native:让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用 v-on 只会监听自定义事件

    鼠标按钮修饰符

    鼠标按钮修饰符针对的就是左键、右键、中键点击,有如下:

    • left 左键点击:<button @click.left="shout(1)">ok</button>
    • right 右键点击:<button @click.right="shout(1)">ok</button>
    • middle 中键点击:<button @click.middle="shout(1)">ok</button>

    键盘修饰符

    键盘修饰符是用来修饰键盘事件(onkeyup,onkeydown)的,有如下:

    keyCode存在很多,但vue为我们提供了别名,分为以下两种:

    普通键(enter、tab、delete、space、esc、up...)

    系统修饰键(ctrl、alt、meta、shift...)

    <input type="text" @keyup.keyCode="shout()"> //只有按键为keyCode的时候才能触发
    

    还可以通过以下方式自定义一些全局的键盘码别名

    Vue.config.keyCodes.f2 = 113
    

    v-bind修饰符

    v-bind修饰符主要是为属性进行操作,用来分别有如下:

    • async:能对props进行一个双向绑定
    //父组件
    <comp :myMessage.sync="bar"></comp> 
    //子组件
    this.$emit('update:myMessage',params);
    

    使用async需要注意以下两点:

    • 使用sync的时候,子组件传递的事件名格式必须为update:value,其中value必须与子组件中props中声明的名称完全一致
    • 注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用
    • 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的
    • prop:设置自定义标签属性,避免暴露数据,防止污染HTML结构
    <input id="uid" title="title1" value="1" :index.prop="index">
    
    • camel:将命名变为驼峰命名法,如将view-Box属性名转换为 viewBox
    • ​​
  • 应用场景

    根据每一个修饰符的功能,我们可以得到以下修饰符的应用场景:

    .stop:阻止事件冒泡

    .native:绑定原生事件

    .once:事件只执行一次

    .self :将事件绑定在自身身上,相当于阻止事件冒泡

    .prevent:阻止默认事件

    .caption:用于事件捕获

    .once:只触发一次

    .keyCode:监听特定键盘按下

    .right:右键

1.30.Webpack怎么理解 具体解决了 什么问题?

Webpack 最初的目标是实现前端项目的模块化,旨在更高效地管理和维护项目中的每一个资源,是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)

模块化: 最早的时候,我们会通过文件划分的形式实现模块化,也就是将每个功能及其相关状态数据各自单独放到不同的JS 文件中

约定每个文件是一个独立的模块,然后再将这些js文件引入到页面,一个script标签对应一个模块,然后调用模块化的成员

减小代码包体积, 让浏览器更快速打开网页

1.31.三次握手 ,四次挥手

TCP三次握手:可靠的传输协议 ​ 2.1 浏览器->服务器 :在吗?能听到我说话吗?(浏览器发送 ok) ​ 2.2 服务器->浏览器 :我在,听到了 你能听到我说话吗?(服务器接收ok 发送 ok) ​ 2.1 浏览器->服务器 :我也听到你说话了,咱们开始吧(浏览器发送 ok)

TCP 四次挥手。

1.TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。 (浏览器发起通知,请求已经发送完毕,你准备关闭吧)

2.服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。 (服务器发起通知,请求已经已经接收完毕,你准备关闭吧)

3.服务器关闭客户端的连接,发送一个FIN给客户端。 (服务器发起通知,响应报文已经发送完毕,你准备关闭吧)

4.客户端发回ACK报文确认,并将确认序号设置为收到序号加1。 (浏览器发起通知,我准备关闭了,你也准备关闭吧)

1.32.小程序 登录和 支付流程 。

登录

支付流程

1.33.mvvm的理解

MVC

  • 前端的MVC 与后端类似,具备着 View、Controller 和 Model。

    • Model:负责保存应用数据,与后端数据进行同步。
    • Controller:负责业务逻辑,根据用户行为对 Model 数据进行修改。
    • View:负责视图展示,将 Model 中的数据可视化出来。

三者形成了一个如图所示的模型:

MVVM

ViewModel 通过实现一套数据响应式机制自动响应Model中数据变化; 同时 Viewmodel 会实现一套更新策略自动将数据变化转换为视图更新; 通过事件监听响应View中用户交互修改 Model 中数据。 这样在 ViewModel 中就减少了大量DOM操作代码。 MVVM 在保持 View 和 Model 松耦合的同时,还减少了维护它们关系的代码,使用户专注于业务逻辑,兼顾开发效率和可维护性。

1.34.路由的传参有几种方式

1、通过params方式传参

通过$route.push的path携带参数方式 (路由配置中指定参数)

这种方式参数是以/id跟在url后,刷新页面后参数不会丢失。

通过$route.push的params传参 (路由配置中未指定参数)

这种方式的传参,必须使用name进行跳转,未在路由配置:id,url后不会显示id,刷新页面后 参数会丢失。

2、通过query方式传参

这种方式的参数以?id跟在url后,类似get传参,并且,query必须使用path进行传参。刷新页面后参数不会丢失。

1.35.组件的缓存用过哪些

keep-alive

06 项目中常见的问题

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

登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token

拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会

根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。

权限验证:通过token获取用户对应的 权限,动态根据用户的 权限算出其对应有权限的路由,通过

router.addRoutes 动态挂载这些路由

\