前端面试题

简介: 本文整理了前端面试中的核心知识点,涵盖HTML5新特性、CSS3属性、JavaScript基础(数据类型、闭包、原型链)、ES6+语法、Vue框架原理及生命周期、React组件通信、网络协议、浏览器渲染机制等内容,帮助开发者系统复习与提升。

前端面试题

基础类问题
h5的新特性

html5

备注

只有一种 DOCTYPE ⽂件类型声明(统 一标准)

<!DOCTYPE html>

增加了一些新的标签元素(功能, 语义化)

section, video, progress, nav, meter, time, aside, canvas, command, datalist, details, embed, figcaption, figure, footer, header, hgroup...

input 支持了几个新的类型值

date, email, url 等等

新增了一些标签属性

charset(⽤于 meta 标签);async(⽤于 script 标 签)

新增的全域属性

contenteditable, draggable... hidden...

新增API

本地存储, 地理定位, Canvas绘图, 拖拽API, 即时通信 WebSocket

css3新增的特性
说出下方常用的即可, 无需全部背出
1伪元素
2弹性布局flex
3媒体查询
4圆角
5渐变
6阴影
7平面转换
83D转换
9动画
盒子/图片水平垂直居中:
要使一个盒子水平和垂直居中,最简单的方法是使用 CSS 的 flex 布局。
首先,让父元素使用 display: flex 并设置 align-items: center 和 justify-content: center,这样父元素就会在水平和垂直方向上居中。然后,将子元素设置为盒子即可。
下面是一个示例:
如果你希望盒子在垂直方向上居中,但在水平方向上靠左或靠右,则可以使用 justify-content: flex-start 或 justify-content: flex-end。
如果你想使用其他布局方式来实现居中,也可以使用 position: absolute 和 transform: translate(-50%, -50%)。
还有其他一些方法可以实现居中,但上述方法是最常用的。
css盒模型:
CSS盒模型是用于描述HTML元素的布局的一种方法。它用于在浏览器中渲染HTML元素的边框和内容。
每个HTML元素都是一个盒子,其中包含元素的内容,内边距(padding),边框和外边距(margin)。
在CSS中,你可以使用多种属性来控制盒模型的外观和布局,包括:
width和height属性用于控制元素的内容区域的大小。
padding属性用于控制元素的内边距。
border属性用于控制元素的边框。
margin属性用于控制元素的外边距。
你还可以使用box-sizing属性来控制元素的盒模型类型。默认情况下,HTML元素使用的是“标准盒模型”,在这种情况下,元素的宽度和高度仅指内容区域的宽度和高度。但是,你也可以将box-sizing属性设置为“边距盒模型”,在这种情况下,元素的宽度和高度将包括内边距和边框。
块级元素和行内元素:
在HTML中,元素可以分为两种类型:块级元素和行内元素。
块级元素:
块级元素在文档流中占据一整行。
块级元素可以设置宽度和高度。
块级元素可以设置内外边距和边框。
常见的块级元素包括:div,h1,p,form,header,footer,section等。
行内元素:
行内元素在文档流中只占据所需的空间。
行内元素不能设置宽度和高度。
行内元素只能设置内边距。
常见的行内元素包括:a,span,button,input,label,select等。
注意:元素的类型并不是固定的,你可以使用CSS的display属性来改变元素的类型。例如,你可以将一个行内元素转换为块级元素,或者将一个块级元素转换为行内元素。
css选择器权重值:
在CSS中,选择器的权重值(也称为优先级)是用于确定哪些样式规则应该应用到HTML元素的一种机制。
选择器的权重值由两部分组成:选择器的特殊性和样式定义的位置。
选择器的特殊性是根据选择器中使用的各种类型的选择器来计算的。每种类型的选择器都有一个固定的权重值,如下表所示:

选择器类型

权重值

通配符(*)

0

元素选择器(例如p)

1

类选择器(例如.class)

10

ID选择器(例如#id)

100

属性选择器(例如[type])

10

伪类选择器(例如:hover)

10

伪元素选择器(例如::before)

10

为了计算选择器的特殊性,需要对选择器中使用的每种类型的选择器的权重值进行加权。例如,如果选择器为#id .class p,则其特殊性为(100 * 1) + (10 * 1) + (1 * 1) = 111。
样式定义的位置也会影响选择器的权重值。在所有其他因素相同的
的情况下,样式定义出现的位置越靠后,其权重值就越大。这意味着如果有多个样式规则适用于同一个HTML元素,那么最后出现的样式规则会覆盖先前出现的样式规则。
为了确定哪些样式规则应用到HTML元素,浏览器会比较所有适用于该元素的样式规则的权重值,并应用权重值最大的样式规则。
你可以使用!important来强制应用样式规则,即使其权重值低于其他样式规则。例如,如果你想要强制应用某个样式规则,你可以在样式值后面添加!important,例如:
这将强制将所有段落的文本颜色设置为红色,即使有其他样式规则为段落设置了不同的颜色。注意,使用!important会使样式规则的权重值变得非常高,因此应该谨慎使用。
H5事件:
onblur失焦事件
onfocus聚焦事件
onchange改变事件
onclick点击事件
onerror错误事件
oninput输入事件
onkeydown键盘按下事件
onkeyup键盘抬起事件
onmousemove鼠标移动事件
onmouseover鼠标进入事件
onmouseout鼠标移出事件等
H5中input元素的type属性值:
color颜色
password密码
text文本
CheckBox复选框
radio单选框
date日期
button按钮
submit提交按钮等

基础相关
js数据类型:
JavaScript有七种数据类型:
1字符串(String):用于表示文本数据。例如:"hello world"。
2数字(Number):用于表示数值数据。例如:42。
3布尔(Boolean):用于表示真假值。例如:true或false。
4undefined:用于表示未定义的值。
5null:用于表示空值。
6对象(Object):用于表示各种类型的数据的集合。例如:{name: "John", age: 30}。
7数组(Array):用于表示一组有序的值的集合。例如:[1, 2, 3]。
JavaScript还有一种数据类型叫做函数(Function),它是一个可执行的代码块,可以被当作数据来使用。
你可以使用typeof运算符来检查一个变量的数据类型。例如:
注意,使用typeof运算符检查数组和null的数据类型时会返回"object"。因此,如果你想要确定一个变量是否是数组或null,你可以使用其他方法,例如使用Array.isArray()方法来检查一个变量是否是数组,或者使用双等号(==)进行比较来检查一个变量是否是null。例如:
此外,JavaScript还有一种特殊的数据类型叫做符号(Symbol),它用于创建唯一的值。你可以使用Symbol()函数来创建一个符号,例如:
符号是JavaScript的一种新的数据类型,可以用来创建唯一的标识符,例如在对象的属性名称中使用。因为符号是唯一的,所以你可以使用它来防止属性名称冲突。例如:
注意,使用符号作为对象属性名称时,需要在属性名称前后添加方括号,这样才能正确地将属性名称解析为符号。
11、回流和重绘:
回流(reflow)是指当浏览器渲染HTML页面时,对页面布局和几何的计算过程。当页面中的元素的大小、位置或布局方式改变时,浏览器就需要进行回流来调整布局。
重绘(repaint)是指当浏览器渲染HTML页面时,对页面中元素的外观进行更新的过程。当页面中元素的颜色、字体或其他外观属性改变时,浏览器就需要进行重绘来更新外观。
回流和重绘都是浏览器在渲染HTML页面时执行的必要过程,但是它们都有一定的开销,因此应该尽量避免不必要的回流和重绘。例如,你可以使用优化的CSS选择器和结构来减少回流的次数,或者使用缓存来避免重复的重绘。
注意,在JavaScript中有一些操作会触发回流和重绘
,例如:
改变HTML元素的尺寸或位置,例如使用offsetWidth、offsetHeight、offsetLeft、offsetTop等属性。
改变HTML元素的布局方式,例如使用display、position、float等属性。
改变HTML元素的外观,例如使用color、background-color、font-size等属性。
你可以使用浏览器的开发工具来查看页面的回流和重绘次数,以及每次回流和重绘的原因。这有助于你发现并优化页面的性能问题。
此外,你还可以使用requestAnimationFrame()函数来让浏览器在下一次重绘之前执行特定的代码。这可以让你在更新页面元素的外观时,将多个操作合并成一次重绘,从而减少重绘的次数。例如:
注意,requestAnimationFrame()函数是异步执行的,因此你不能依赖它来控制代码的执行顺序。
12、闭包:
闭包是一种特殊的对象,它包含了一个函数和与该函数相关的引用环境。
闭包的函数可以访问闭包创建时的环境,即使在该函数被调用时,外部的环境已经发生了变化。这使得闭包很适合用来做回调函数或者保存状态。
举个例子,假设你有一个函数,它接受一个数字作为参数,并返回一个函数。该返回的函数可以对传入的数字进行累加,每次调用都会将累加器加 1:

COPY CODE

ER(X)

FUNCTION CREATEADDER ( A

RETURN FUNCTION(Y) (

RETURN X + Y;

CONST ADD5 - CREATEADDER(5);

CONSOLE. LOG(ADD5(2));

CONSOLE. LOG(ADD5(10)); / 15


在上面的例子中,createAdder 函数创建了一个闭包,该闭包包含了一个函数和与该函数相关的环境。这个环境包含了变量 x 的值。当我们调用 createAdder(5) 时,它返回了一个新函数,这个函数可以对传入的参数 y 进行累加。在这个函数中,变量 x 的值是 5,所以调用 add5(2) 和 add5(10) 时,都会将它们的参数与 5 相加。
闭包是一种非常有用的技术,它可以帮助你保存状态、创建封装的函数等

13、原型和原型链:
在JavaScript中,每个对象都有一个原型(prototype),它是另一个对象。原型对象可以包含属性和方法,这些属性和方法可以被对象继承。这种继承机制被称为原型链(prototype chain)。
例如,你可以定义一个Person构造函数来表示人,并在Person.prototype中定义sayHello方法,表示人会说话:
在上面的例子中,john是Person类型的对象,它继承了Person.prototype中的sayHello方法。你可以使用instanceof运算符来检查一个对象是否是某个类型的实例,例如:
注意,每个对象都有一个constructor属性,表示该对象的构造函数。你可以使用constructor属性来检查一个对象的类型,例如:
此外,每个对象还有一个__proto__属性,表示该对象的原型。你可以使用__proto__属性来检查一个对象的原型对象,例如:

14、this指向问题:
在 JavaScript 中,this 关键字的指向可能有以下几种情况:
1在全局作用域中,this 指向全局对象。在浏览器中,全局对象是 window,在 Node.js 中,全局对象是 global。
2在函数中,默认情况下,this 指向全局对象。但是,如果将函数作为对象的方法调用,则 this 指向调用方法的对象。
3在箭头函数中,this 的指向是定义时所在的作用域的 this。箭头函数没有自己的 this,因此它永远不会改变指向。
4可以使用 call、apply 或 bind 方法显式地指定 this 的指向。
例如:

15、数组中forEach和map:
forEach 和 map 是 JavaScript 中常用的数组方法,都可以用来遍历数组中的元素,但是它们之间有一些区别:
1功能不同:forEach 方法是遍历数组的方法,它提供了一种快捷的方式来遍历数组的所有元素。而 map 方法是映射数组的方法,它可以根据指定的规则对数组的每个元素进行映射,并返回一个新的数组。
2返回值不同:forEach 方法不会返回任何值,只会对数组的每个元素执行回调函数。而 map 方法会返回一个新的数组,该数组的元素是对原数组中每个元素执行回调函数之后的返回值。
3处理流程不同:forEach 方法是按顺序依次对数组的每个元素执行回调函数。而 map 方法是同时对数组的每个元素执行回调函数,并将结果放入新的数组中。
总的来说,forEach 和 map 是两种常用的数组方法,但是它们的功能、返回值和处理流程都有所不同。根据自己的需要,可以选择适合自己的方法进行使用。

16、 call、bind、apply ( 函数上下文调用模式 ) :
JavaScript 提供了三种方法来改变函数的调用上下文:call、bind 和 apply。
call 方法允许您将函数的调用上下文指定为某个对象,并传递一些参数给函数。这样可以在不同的上下文中调用同一函数。例如:
在上面的示例中,我们将函数 greet 的调用上下文指定为 person 对象,并传递了一个参数 'Hello'。这样,函数中的 this 将指向 person 对象,并返回 "Hello, John!"。
bind 方法与 call 类似,但它并不立即调用函数,而是返回一个新函数,该函数的调用上下文已被指定为您提供的对象。例如:
在上面的示例中,我们使用 bind 方法将函数 greet 的调用上下文指定为 person 对象,并返回了一个新函数 greetJohn。当我们调用 greetJohn 时,它的调用上下文已被指定为 person,并返回 "Hello, John!"。
apply 方法与 call 类似,但它允许您使用数组来传递参数,而不是使用单独的参数列表
另外,还有几点需要注意:
在使用 call 或 apply 时,您必须立即调用函数,而 bind 方法则返回一个新函数。
在使用 bind 方法时,您可以通过在绑定时提供额外的参数来为新函数指定参数。例如:
在这种情况下,新函数 greetJohnHello 将固定使用参数 'Hello',无论您在调用时提供了什么参数。
17、new操作符具体过程:
使用 new 操作符创建一个新对象的过程如下:
1创建一个新对象。
2将这个新对象的原型设置为构造函数的原型。
3将这个新对象的 this 设置为这个新对象。
4如果构造函数返回了对象,则返回这个对象;否则,返回这个新对象。
例如,下面是使用 new 操作符创建一个新对象的示例:
在这个例子中,我们定义了一个构造函数 Person,然后使用 new 操作符创建了一个新的 Person 对象,并将其赋值给变量 john。这个新对象继承了 Person.prototype 上的属性和方法,并且其 this 被设置为这个新对象。
注意,使用 new 操作符创建对象时,构造函数中的代码会在新对象上执行,并且新对象会继承构造函数的原型。因此,在上面的示例中,新对象 john 具有名为 name 的属性,并且可以调用 Person.prototype 上的 greet 方法。
在使用 new 操作符时,还有几点需要注意:
如果构造函数返回了对象,则返回这个对象,而不是这个新对象。这意味着,如果构造函数中的代码显式地返回了一个对象,则这个对象将作为最终结果返回,而新创建的对象将被忽略。例如:
在这个例子中,构造函数返回了一个对象,因此最终结果是这个对象,而不是新创建的对象。
如果构造函数返回了原始值(例如数字、字符串或布尔值),则忽略该值并返回新对象。例如:
在这个例子中,构造函数返回了数字 42,但最终结果仍然是新创建的对象。
如果构造函数没有返回值,则默认返回新对象。例如:
在这个例子中,构造函数没有返回值,因此最终结果是新创建的对象。
总之,new 操作符创建一个新对象并使用构造函数初始化它。它还会将新对象的原型设置为构造函数的原型,并且在构造函数执行时将 this 设置为新对象。如果构造函数返回了对象,则返回这个对象;否则,返回新对象。
使用 new 操作符是 JavaScript 中常见的模式,可以使用它来创建具有共同属性和方法的对象,并使用构造函数的原型链来为这些对象提供共享的功能。
18、浅拷贝和深拷贝:
深拷贝和浅拷贝是指在复制对象时,复制的方式不同。
浅拷贝只是复制对象的引用,并不会复制对象本身。如果对象是基本类型,则复制的是值本身;如果对象是引用类型,则复制的是指向对象内存地址的指针。因此,如果对象是引用类型,则拷贝后的对象和原对象指向的是同一块内存,任意一方的修改都会影响另一方。
深拷贝则是完全复制了对象本身,包括对象内部的所有属性和方法。深拷贝后的对象和原对象没有任何关联,对其中一方的修改不会影响另一方。
在 JavaScript 中,可以使用以下方法实现深拷贝:
1使用 JSON 序列化和反序列化。这种方法适用于简单对象和数组,但不能复制函数、正则表达式、日期等对象。

COPY CODE

DEEPCOPY (OB J)

FUNCTION

RETURN JSON. PARSE(JSON.STRINGIFY(OBJ);


使用递归算法。这种方法可以复制任意类型的对象

COPY CODE

FUNCTION DEEPCOPY(OBJ) (

OBJ - NULL)

OB JECT'

IF (TYPEOF OBJ !

RETURN OBJ;

LET COPY - ARRAY. ISARRAY(OBJ) ? [] : {;

FOR (LET KEY IN OBJ) (

COPY[KEY] - DEEPCOPY(OBJ[KEY]);

RETURN COPY;


另外,JavaScript 中还有一种浅拷贝的方法:使用 Object.assign() 函数。这个函数可以把一个或多个源对象的所有可枚举属性复制到目标对象中。

COPY CODE

LET OBJ { A: 1, B: 2};

LET COPY - OBJECT.ASSIGN(), OB)

OBJ);


这种方法只能复制对象的属性,对于对象的方法和属性值为对象的属性,不会进行复制。

19、js事件循环:
JavaScript 是一种单线程语言,这意味着只能执行一个任务。但是,JavaScript 引擎会在后台持续执行一些任务,例如响应用户的输入、下载网络资源等。这些任务是由事件循环管理的。
事件循环是一种机制,用于在执行主线程的同时处理异步任务。它按照以下步骤工作:
1主线程执行同步任务。
2当遇到异步任务时,将其排入队列中。
3当主线程空闲时,从队列中取出第一个任务并执行。
4当任务完成时,如果有回调函数,则将其排入队列中。
5重复步骤 1-4,直到主线程的任务完成。
例如,下面是一个使用事件循环的示例:
在这个例子中,事件循环会执行以下步骤:
执行 console.log('Start')。
遇到 setTimeout 函数,将其排入队列中。
执行 console.log('End')。
一秒钟后,从队列中取出第一个任务并执行 console.log('Timeout')。

20、防抖和节流:
防抖和节流是两种常见的控制函数执行频率的方法,常用于限制用户的输入频率或频繁触发的事件。
防抖(debouncing)是指在一定时间内只执行最后一次触发事件,在这个时间内如果有新的触发事件,会取消之前的触发事件并重新计时。防抖通常用于限制输入频率,比如在输入框中输入文本,或者在搜索框中输入关键字。
节流(throttling)是指在一定时间内只执行一次事件,在这个时间内如果有新的触发事件,会忽略这个事件,等到这个时间结束后才会执行。节流通常用于限制事件触发的频率,比如在滚动条事件中执行实时网络请求,调整窗口大小事件等。
以下是一个简单的防抖函数的实现:
使用方法:
以下是一个简单的节流函数的实现:
使用方法:

需要注意的是,防抖和节流的效果是有区别的。防抖会延迟执行函数,直到输入停止一段时间后才执行;而节流会保证函数在一定时间内只执行一次,如果在这段时间内有多次触发事件,只有第一次会被执行。根据实际需求来选择使用防抖还是节流。
21、ES6新增方法:

ECMAScript 6(也称为 ECMAScript 2015)是 JavaScript 的下一代标准,提供了很多新的特性。下面是一些常见的新增特性:
let 和 const 关键字:这两个关键字用于声明变量,其中 let 声明的变量可以被修改,而 const 声明的变量是常量,不能被修改。
箭头函数(Arrow functions):这是一种简化函数的语法,它比传统的函数定义更短、更简洁。例如,你可以使用箭头函数来声明一个简单的函数,如下所示:
块级作用域:在 ES6 中,你可以使用 let 和 const 在代码块(如 for 循环或 if 语句)内声明变量。这意味着这些变量只在声明它们的代码块内可用,而不是整个函数内可用。
类(Classes):ES6 中引入了类的概念,使得创建和维护对象变得更加容易。你可以使用类来声明新的对象类型,并使用类的构造函数来创建新的对象实例。
模板字符串(Template literals):模板字符串是一种新的字符串表示方式,使用反引号(`)包围,允许模板字符串内插变量。例如,你可以使用如下的模板字符串来创建带有变量的字符串:
解构赋值(Destructuring assignment):解构赋值是一种方便的方法,可以在一个表达式中提取数组或对象的多个值。例如,你可以使用解构赋值将对象的属性赋值给变量,如下所示:
这些只是 ES6 中的一些新增特性,还有许多其他的特性,例如 Promises、Iterators、Generators、Modules 等。

22、set和map的区别:
JavaScript 中的 Set 和 Map 是两种常用的数据结构,它们都是用于存储数据的容器,但是它们有一些区别。
Set:
Set 是一种无序的数据集合,其中的元素都是唯一的。Set 中的元素可以是任意类型的值。
Set 支持的操作包括添加、删除、查找和枚举,可以使用 for-of 循环来遍历 Set 中的所有元素。
Set 是一种新的数据结构,它在 ECMAScript 2015 中引入。
Map:
Map 是一种无序的键值对集合,其中的元素都是以键值对的形式存储的。Map 中的键和值可以是任意类型的值。
Map 支持的操作包括添加、删除、查找和枚举,可以使用 for-of 循环来遍历 Map 中的所有元素。
Map 也是一种新的数据结构,它在 ECMAScript 2015 中引入。
在使用时,应根据实际需求来选择使用 Set 或 Map。如果你需要存储一组唯一的数据,可以使用 Set;如果你需要存储一组键值对数据,可以使用 Map。
以下是一个简单的 Set 的使用示例:
在这个示例中,我们创建了一个 Set 对象,并通过构造函数传入了一个数组 [1, 2, 3, 4, 5]。然后我们使用 Set 的 has() 方法来检查 Set 中是否存在某个元素。接下来我们使用 add() 方法向 Set 中添加一个新元素 6,并使用 delete() 方法删除 Set 中的元素 5。最后我们使用 for-of 循环遍历 Set 中的所有元素。
以下是一个简单的 Map 的使用示例:
在这个示例中,我们创建了一个 Map 对象,并通过构造函数传入了一个数组 [ ['name', 'John'], ['age', 30] ]。然后我们使用 Map 的 get() 方法来获取 Map 中的元素值。接下来我们使用 set() 方法向 Map 中添加一个新的键值对 ['country', 'USA'],并使用 delete() 方法删除 Map 中的键值对 ['age', 30]。最后我们使用 for-of 循环遍历 Map 中的所有元素。
23、点击穿透现象及解决办法:
点击穿透是指在使用移动设备浏览网页时,当用户点击屏幕上的某一元素时,点击事件会同时触发下方的元素。这种现象通常发生在设计中使用了透明或半透明背景的元素上。
要解决这个问题,你可以采取以下几种方法:
1使用不透明的背景:为触发点击穿透的元素使用不透明的背景,这样就不会出现点击穿透的现象了。
2给元素添加边框:为触发点击穿透的元素添加边框,这样就可以使用边框来阻止点击事件穿透到下方的元素。
3使用 JavaScript 来阻止点击穿透:可以使用 JavaScript 代码来阻止点击事件穿透到下方的元素。你可以在元素上添加一个点击事件监听器,并在事件处理函数中调用 event.preventDefault() 方法来阻止默认的点击行为。
4使用 CSS 属性 pointer-events: none:你可以使用这个 CSS 属性来禁用元素的点击事件。这样就可以阻止点击穿透的现象了。
5使用 CSS 伪类 :active:你可以使用 :active 伪类来模拟点击效果,从而避免点击穿透的现象。你可以在元素的样式中使用 :active 伪类来设置点击时的样式,例如:
这样,当用户点击按钮时,按钮的背景颜色会变成蓝色。这种方法可以在不使用 JavaScript 的情况下解决点击穿透的问题。
总之,点击穿透是一个常见的问题,但是有很多方法可以解决这个问题。你可以根据自己的需求来选择最合适的方法来解决点击穿透的问题。
24、js的继承:
原型链继承:让新实例的原型等于父实例
可继承:实例的构造函数的属性,父类构造函数属性,以及父类原型的属性
不可继承:父类实例的属性
借用构造函数继承:使用 apply()和 call()方法将父类构造函数引入子类函数
可继承:父类构造函数的属性
不可继承父类原型的属性
组合继承:将原型链和借用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式
原型式继承:借助原型可以基于已有的对象创建新对象,类似复制了一个对象
寄生式继承:就是给原型式继承外面套个壳子,没用到原型
寄生组合式继承:通过借用函数来继承属性,通过原型链的混成形式来继承方法(常用)

25、如何理解promise:
Promise 是一种用于异步编程的解决方案,它可以让你以同步的方式编写异步代码。
在 JavaScript 中,很多操作都是异步的,例如网络请求、读取文件或等待用户输入。这些操作会在后台运行,因此你不能直接等待它们完成,而是需要提供一个回调函数,在操作完成时调用。
Promise 可以解决这种回调地狱的问题,它使用一种称为链式调用的方法,让你能够在 then 方法中连续调用多个异步操作。
例如,你可以使用 Promise 发起一个网络请求,然后在请求完成后调用回调函数。你可以使用 then 方法来处理请求结果,如下所示:
在这个例子中,axios.get 方法会发起一个网络请求,然后返回一个 Promise。你可以在 then 方法中提供一个回调函数来处理响应数据,然后再次使用 then 方法来处理解析后的数据。如果在任何阶段发生错误,你可以使用 catch 方法来处理错误。
这种方法使得异步编程变得更加简单,因为你不再需要写很多嵌套的回调函数。你可以使用 then 方法链式调用多个异步操作,而不用担心回调地狱的问题。
Promise 还有一些其他的特性,例如你可以使用 Promise.all 方法来并行执行多个 Promise,或者使用 Promise.race 方法来执行多个 Promise 中最先完成的那个。你还可以使用 Promise.resolve 和 Promise.reject 方法来创建已完成或已拒绝的 Promise。
总之,Promise 是一种有用的工具,可以让你在异步编程中更加简单、灵活地处理异步操作。
27、 async/await的理解:
async/await 是 JavaScript 中的一种语法,用于处理异步任务。
async 关键字用于修饰函数,表示该函数是一个异步函数。异步函数返回一个 Promise 对象,表示异步操作的结果。
await 关键字用于在异步函数内部等待一个 Promise 对象的完成。当使用 await 关键字时,JavaScript 会暂停执行异步函数,等待 Promise 对象完成,然后再继续执行异步函数。
例如,我们可以使用 async/await 来等待一个异步函数的执行结果:
在这个例子中,getData 函数是一个异步函数,它会发送一个 HTTP 请求获取数据,然后使用 await 关键字等待 HTTP 请求的结果。
async/await 语法的优点在于可以让异步代码看起来像同步代码一样,更容易阅读和维护。你可以在 await 后面跟任何返回 Promise 对象的函数或表达式,例如 fetch 或者自定义的异步函数。
需要注意的是,async/await 语法只能在 async 函数内部使用,如果在其他地方使用会导致语法错误。另外,使用 await 关键字时,必须确保在 await 后面跟的是一个返回 Promise 对象的函数或表达式,否则会抛出错误。
使用 async/await 语法时,你还可以使用 try/catch 语句来捕获异步函数中可能出现的错误。例如:
在这个例子中,如果在发送 HTTP 请求或者解析响应数据时出现错误,就会执行 catch 块中的代码来处理错误。
总之,async/await 语法是一种方便的方法来处理异步任务,可以让异步代码看起来更像同步代码,使得代码更容易阅读和维护。
作用域:
在 JavaScript 中,作用域是指程序中定义变量和函数的区域。一般来说,变量和函数在它们被声明的地方可用,并且其他地方不可用。
JavaScript 中有两种类型的作用域:全局作用域和局部作用域。
全局作用域:全局作用域是整个程序的范围。在全局作用域中声明的变量和函数可在整个程序的任何地方使用。如果在函数内部声明的变量没有使用 var 关键字,则该变量也是全局变量。
局部作用域:局部作用域是在函数内部定义的作用域。在局部作用域中声明的变量和函数仅在函数内部可用,在函数外部不可用。使用 var 关键字声明的变量是局部变量,如果没有使用 var 关键字,则该变量是全局变量。
举个例子:

CODE

//全局变量

VAR GLOBALVARIABLE - "THIS IS A GLOBAL

VARIABLE" ;

全局函数

FUNCTION

GLOBALFUNCTION

'THIS IS A GLOBAL FUNCTION') (

CONSOLE. LOG

/局部变量

FUNCTION LOCALSCOPE ()

VAR LOCALVARIABLE

"THIS IS A LOCAL VARIABLE"

LOG(LOCALVARIABLE);

CONSOLE...

LOCALSCOPE();//输出"THIS IS A LOCAL

VARIABLE"

错误

CONSOLE.LOG(LOCALVARIABLE);//抛出

REFERENCEERROR

//输出"THIS IS A GLOBAL FUNCTION"

GLOBALFUNCTION (

CONSOLE.LOG (GLOBALVARIABLE);/ 输出" THIS IS IS A GLOBAL VARIABLE


上面的代码中,globalVariable 和 globalFunction 是全局变量和函数,它在整个程序的任何地方都可以访问。localScope 函数中的 localVariable 是局部变量,只能在函数内部访问,在函数外部访问会抛出 ReferenceError 错误。
另外,JavaScript 中还有一个概念叫做闭包,它可以让我们在函数外部访问函数内部的局部变量。这是通过在函数内部返回另一个函数来实现的。
举个例子:

COPY CODE

FUNCTION OUTERFUNCTION(

"THIS IS AN OUTER VARIABLE"

VAR OUTERVARIABLE

FUNCTION INNERFUNCTION(

RETURN

CONSOLE.LOG(OUTERVARIABLE);

OUTERFUNCTION(

VAR INNERFUNC

INNERFUNC();//输出 THIS IS AN OUTER VARIABLE


在上面的代码中,outerFunction 函数返回了一个匿名函数,这个匿名函数被赋值给了 innerFunc 变量。调用 innerFunc 函数会输出 outerVariable 的值,尽管 outerVariable 是在函数内部声明的局部变量。这是因为闭包使得函数内部的局部变量能够在函数外部访问。
事件对象和事件委托:
事件对象:
一个函数或者方法都会带有一个事件对象参数
事件对象.target是获取最先触发的元素
事件对象有两种公共的方法:
.preventDefault() 阻止默认行为
.stopPropagation()阻止冒泡
事件委托:
可以把事件处理器添加到一个上级元素上,避免把事件处理器添加到多个子元素上,提高性能
还可以预测未来,动态添加的元素仍然可以触发该事件
主要依靠的就是事件冒泡,也就是当一个元素接收到事件的时候,会把他接收到的事件传给自己的父级,一直到window

sessionStorage和localStorage的区别
sessionStorage 和 localStorage 是两种存储数据的方式,都可以用来保存在浏览器中的数据。但是,它们之间有一些区别:
1存储范围不同:sessionStorage 只在浏览器的当前会话中有效,当会话结束(浏览器关闭)时,数据就会被清除。而 localStorage 在浏览器中是持久的,除非用户手动清除数据或者浏览器清除缓存,否则数据不会丢失。
2存储容量不同:一般来说,sessionStorage 和 localStorage 的存储容量都是有限的。但是,localStorage 的容量通常比 sessionStorage 大一些,具体数值取决于浏览器的具体实现。
3使用方法不同:sessionStorage 和 localStorage 的使用方法基本相同,都可以使用 setItem() 和 getItem() 方法来存储和获取数据。但是,在使用时,需要注意区分两者的作用域。
总的来说,sessionStorage 和 localStorage 都是用于存储浏览器中的数据的方式,但是它们在存储范围、容量和使用方法等方面有一些区别。在选择使用哪种存储方式时,应该根据自己的需要进行选择。

1功能相似,
2不同点
alocalStorage: 页面关闭数据不丢失,具有永久性质。除非主动删除数据。
bsessionStorage:页面关闭,数据会自动清除
rem和em
rem 和 em 都是用于设置字体大小的单位,它们的区别在于计算方式不同。
rem(Root em)是相对于根元素的字体大小的单位。也就是说,如果你在根元素(一般是 html 元素)中设置了字体大小,那么所有使用 rem 单位的字体大小都会相对于根元素的字体大小进行计算。
em(em)是相对于父元素的字体大小的单位。也就是说,如果你在父元素中设置了字体大小,那么所有使用 em 单位的字体大小都会相对于父元素的字体大小进行计算。
例如,如果你在根元素中设置了字体大小为 16px,并在一个子元素中使用了 rem 单位设置字体大小为 2rem,那么子元素的字体大小就会是 32px(2 * 16px)。如果你在子元素中使用了 em 单位设置字体大小为 2em,那么子元素的字体大小就会是 32px(2 * 16px)。
一般来说,rem 单位更常用于设置整个网站的字体大小,因为它是相对于根元素计算的,可以方便地在整个网站中控制字体大小。而 em 单位更常用于设置单个元素的字体大小

响应式布局
响应式布局是指网站的布局能够根据用户设备的不同尺寸和分辨率进行自适应。这种布局方式可以让网站在不同的设备上都能够很好的呈现,包括电脑、平板电脑、手机等。
下面是一些常用的响应式布局方法:
1使用流式布局(Fluid Layout):流式布局是指使用百分比来设置元素的宽度和高度,而不是固定的像素值。这种布局方式可以让元素在不同的设备上自动调整大小,适应屏幕尺寸的变化。
2使用媒体查询(Media Queries):媒体查询是一种 CSS 技术,可以根据用户设备的屏幕尺寸和分辨率动态地应用不同的样式。这种方式可以让你为不同的设备设置不同的布局和样式。
3使用自适应网格布局(Adaptive Grid Layout):自适应网格布局是指使用网格布局(Grid Layout)技术,在不同的屏幕尺寸下自动调整网格的列数和行数,使得布局看起来更合理。
4使用弹性盒布局(Flexbox Layout):弹性盒布局是一种 CSS 技术,可以让元素在一个容器中自动地按照一定的规则进行布局。它可以让元素在不同的屏幕尺寸下自动调整大小,使得布局看起来更合理
有没有用过视频组件
是的,我曾使用过视频组件。视频组件是一种用于在网页或应用中播放视频的组件,通常使用 HTML5 中的 video 元素来实现。
在使用视频组件时,通常可以指定视频的源文件地址、视频的宽度和高度、是否自动播放等参数。视频组件还可以支持一些常用的控制功能,如播放、暂停、快进、倒退等。
例如,可以使用以下代码来创建一个视频组件:
这样,当网页加载时,就会在网页中自动播放 video.mp4 这个视频文件。
vue中可以使用类似:vue-core-video-player 的组件

为什么会跨域 ?
本质:跨域是浏览器基于同源策略的一种安全手段。
同源策略:
本质:是一种约定, 浏览器 的一种⽤于隔离潜在恶意⽂件的重要安全保护机制。
含义:即指在同一个域
三个相同点:
协议相同(protocol)
主机相同(host)
端口相同(port)
反之非同源请求,也就是协议、端口、主机其中一项不相同的时候,这时候就会产生跨域
不受同源策略影响的有哪些
除了以下三个资源获取类型的标签,在浏览器中,⼤部分内容都受同源策略限制。
<img>
<link>
<script>
跨域怎么处理 ?
跨域是指浏览器访问的网站与请求资源所在的服务器之间存在跨域的情况。在跨域的情况下,浏览器会拒绝访问资源,以保证安全。
对于跨域的情况,通常有以下几种解决方案:
1使用代理服务器:可以在本地搭建一个代理服务器,通过代理服务器转发请求,从而解决跨域问题。
2使用 JSONP:JSONP 是一种跨域数据传输方式,可以通过动态插入 script 标签的方式实现跨域访问,JSONP是比较老的一种方案,只支持get请求,不支持post请求
3使用 CORS:CORS 是一种跨域资源共享的方式,可以通过在服务器端配置 HTTP 头信息,让浏览器允许跨域访问。
4使用 WebSocket:WebSocket 是一种基于 TCP 的协议,可以实现双向通信,不存在跨域的限制。
根据具体情况,可以选择适合自己的跨域解决方案。

forEach与map的区别
forEach 和 map 是 JavaScript 中常用的数组方法,都可以用来遍历数组中的元素,但是它们之间有一些区别:
1功能不同:forEach 方法是遍历数组的方法,它提供了一种快捷的方式来遍历数组的所有元素。而 map 方法是映射数组的方法,它可以根据指定的规则对数组的每个元素进行映射,并返回一个新的数组。
2返回值不同:forEach 方法不会返回任何值,只会对数组的每个元素执行回调函数。而 map 方法会返回一个新的数组,该数组的元素是对原数组中每个元素执行回调函数之后的返回值。
总的来说,forEach 和 map 是两种常用的数组方法,但是它们的功能、返回值和处理流程都有所不同。根据自己的需要,可以选择适合自己的方法进行使用。

es6新增特性
ECMAScript 6(也称为 ECMAScript 2015)是 JavaScript 的下一代标准,提供了很多新的特性。下面是一些常见的新增特性:
let 和 const 关键字:这两个关键字用于声明变量,其中 let 声明的变量可以被修改,而 const 声明的变量是常量,不能被修改。
箭头函数(Arrow functions):这是一种简化函数的语法,它比传统的函数定义更短、更简洁。例如,你可以使用箭头函数来声明一个简单的函数,如下所示:
块级作用域:在 ES6 中,你可以使用 let 和 const 在代码块(如 for 循环或 if 语句)内声明变量。这意味着这些变量只在声明它们的代码块内可用,而不是整个函数内可用。
类(Classes):ES6 中引入了类的概念,使得创建和维护对象变得更加容易。你可以使用类来声明新的对象类型,并使用类的构造函数来创建新的对象实例。
模板字符串(Template literals):模板字符串是一种新的字符串表示方式,使用反引号(`)包围,允许模板字符串内插变量。例如,你可以使用如下的模板字符串来创建带有变量的字符串:
解构赋值(Destructuring assignment):解构赋值是一种方便的方法,可以在一个表达式中提取数组或对象的多个值。例如,你可以使用解构赋值将对象的属性赋值给变量,如下所示:
这些只是 ES6 中的一些新增特性,还有许多其他的特性,例如 Promises、Iterators、Generators、Modules 等。

promise的理解
Promise 是一种用于异步编程的解决方案,它可以让你以同步的方式编写异步代码。
在 JavaScript 中,很多操作都是异步的,例如网络请求、读取文件或等待用户输入。这些操作会在后台运行,因此你不能直接等待它们完成,而是需要提供一个回调函数,在操作完成时调用。
Promise 可以解决这种回调地狱的问题,它使用一种称为链式调用的方法,让你能够在 then 方法中连续调用多个异步操作。
例如,你可以使用 Promise 发起一个网络请求,然后在请求完成后调用回调函数。你可以使用 then 方法来处理请求结果,如下所示:
在这个例子中,axios.get 方法会发起一个网络请求,然后返回一个 Promise。你可以在 then 方法中提供一个回调函数来处理响应数据,然后再次使用 then 方法来处理解析后的数据。如果在任何阶段发生错误,你可以使用 catch 方法来处理错误。
这种方法使得异步编程变得更加简单,因为你不再需要写很多嵌套的回调函数。你可以使用 then 方法链式调用多个异步操作,而不用担心回调地狱的问题。
Promise 还有一些其他的特性,例如你可以使用 Promise.all 方法来并行执行多个 Promise,或者使用 Promise.race 方法来执行多个 Promise 中最先完成的那个。你还可以使用 Promise.resolve 和 Promise.reject 方法来创建已完成或已拒绝的 Promise。
总之,Promise 是一种有用的工具,可以让你在异步编程中更加简单、灵活地处理异步操作。
宏任务和微任务:
Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(microtasks)。宏任务队列可以有多个,微任务队列只有一个
宏任务:(task)
setTimeout, setInterval
微任务:(jobs)
Promise
ES6中var let const的区别
JavaScript 中有三种声明变量的方法:var、let 和 const。它们有如下区别:
var:这是 JavaScript 中最常用的声明变量的方法,可以声明全局变量或函数内的局部变量。var 声明的变量可以被修改,并且存在变量提升的问题。
let:let 是 ES6 中新增的声明变量的方法,它的作用和 var 类似,但是 let 声明的变量只在声明它的代码块内有效,并且不存在变量提升的问题。
const:const 也是 ES6 中新增的声明变量的方法,它声明的是常量,常量的值不能被修改。和 let 一样,const 声明的变量只在声明它的代码块内有效,并且不存在变量提升的问题。
总之,你应该尽量使用 let 和 const 来声明变量,因为它们具有更好的作用域控制和不存在变量提升的问题。只有在必要的时候才使用 var。
例如,你应该使用如下的方式声明变量:

JS的数据类型,储存上的差距
JavaScript 中有几种不同的数据类型,这些数据类型在储存上的差距是有区别的。
原始数据类型:原始数据类型包括布尔值(boolean)、数字(number)、字符串(string)和空值(null)、未定义(undefined)五种。这些数据类型在储存上占用的空间很小,通常只需要几个字节。
对象类型:对象类型包括数组(array)、函数(function)、对象(object)等。这些数据类型在储存上占用的空间相对较大,因为它们可能包含多个属性或方法。
总之,不同的数据类型在储存上的差距是有区别的,你应该根据使用场景来选择合适的数据类型。

数据类型分两大类:
1基本数据类型,变量保存的是值
2引用数据类型,变量保存的是引用地址

闭包的理解和使用
闭包是一种特殊的对象,它包含了一个函数和与该函数相关的引用环境。
闭包的函数可以访问闭包创建时的环境,即使在该函数被调用时,外部的环境已经发生了变化。这使得闭包很适合用来做回调函数或者保存状态。
举个例子,假设你有一个函数,它接受一个数字作为参数,并返回一个函数。该返回的函数可以对传入的数字进行累加,每次调用都会将累加器加 1:

COPY CODE

ER(X)

FUNCTION CREATEADDER ( A

RETURN FUNCTION(Y) (

RETURN X + Y;

CONST ADD5 - CREATEADDER(5);

CONSOLE. LOG(ADD5(2));

CONSOLE. LOG(ADD5(10)); / 15


在上面的例子中,createAdder 函数创建了一个闭包,该闭包包含了一个函数和与该函数相关的环境。这个环境包含了变量 x 的值。当我们调用 createAdder(5) 时,它返回了一个新函数,这个函数可以对传入的参数 y 进行累加。在这个函数中,变量 x 的值是 5,所以调用 add5(2) 和 add5(10) 时,都会将它们的参数与 5 相加。
闭包是一种非常有用的技术,它可以帮助你保存状态、创建封装的函数等

作用域
在 JavaScript 中,作用域是指程序中定义变量和函数的区域。一般来说,变量和函数在它们被声明的地方可用,并且其他地方不可用。
JavaScript 中有两种类型的作用域:全局作用域和局部作用域。
全局作用域:全局作用域是整个程序的范围。在全局作用域中声明的变量和函数可在整个程序的任何地方使用。如果在函数内部声明的变量没有使用 var 关键字,则该变量也是全局变量。
局部作用域:局部作用域是在函数内部定义的作用域。在局部作用域中声明的变量和函数仅在函数内部可用,在函数外部不可用。使用 var 关键字声明的变量是局部变量,如果没有使用 var 关键字,则该变量是全局变量。
举个例子:

CODE

//全局变量

VAR GLOBALVARIABLE - "THIS IS A GLOBAL

VARIABLE" ;

全局函数

FUNCTION

GLOBALFUNCTION

'THIS IS A GLOBAL FUNCTION') (

CONSOLE. LOG

/局部变量

FUNCTION LOCALSCOPE ()

VAR LOCALVARIABLE

"THIS IS A LOCAL VARIABLE"

LOG(LOCALVARIABLE);

CONSOLE...

LOCALSCOPE();//输出"THIS IS A LOCAL

VARIABLE"

错误

CONSOLE.LOG(LOCALVARIABLE);//抛出

REFERENCEERROR

//输出"THIS IS A GLOBAL FUNCTION"

GLOBALFUNCTION (

CONSOLE.LOG (GLOBALVARIABLE);/ 输出" THIS IS IS A GLOBAL VARIABLE


上面的代码中,globalVariable 和 globalFunction 是全局变量和函数,它在整个程序的任何地方都可以访问。localScope 函数中的 localVariable 是局部变量,只能在函数内部访问,在函数外部访问会抛出 ReferenceError 错误。
另外,JavaScript 中还有一个概念叫做闭包,它可以让我们在函数外部访问函数内部的局部变量。这是通过在函数内部返回另一个函数来实现的。
举个例子:

COPY CODE

FUNCTION OUTERFUNCTION(

"THIS IS AN OUTER VARIABLE"

VAR OUTERVARIABLE

FUNCTION INNERFUNCTION(

RETURN

CONSOLE.LOG(OUTERVARIABLE);

OUTERFUNCTION(

VAR INNERFUNC

INNERFUNC();//输出 THIS IS AN OUTER VARIABLE


在上面的代码中,outerFunction 函数返回了一个匿名函数,这个匿名函数被赋值给了 innerFunc 变量。调用 innerFunc 函数会输出 outerVariable 的值,尽管 outerVariable 是在函数内部声明的局部变量。这是因为闭包使得函数内部的局部变量能够在函数外部访问。

this指向
在 JavaScript 中,this 关键字的指向可能有以下几种情况:
1在全局作用域中,this 指向全局对象。在浏览器中,全局对象是 window,在 Node.js 中,全局对象是 global。
2在函数中,默认情况下,this 指向全局对象。但是,如果将函数作为对象的方法调用,则 this 指向调用方法的对象。
3在箭头函数中,this 的指向是定义时所在的作用域的 this。箭头函数没有自己的 this,因此它永远不会改变指向。
4可以使用 call、apply 或 bind 方法显式地指定 this 的指向。
例如:

怎么改变this指向
改变this指向的三种方法:call、apply、bind具体用法和区别参考:https://blog.csdn.net/m0_46412825/article/details/112196928
构造函数在被实例化的时候内部发生了什么

1在内存中新建一个空对象;
2this指向这个内存中的空对象;
3根据定义的键值和传入的参数,依次给这个空对象添加上键值对;
4在构造函数语句末尾添加return this,也就是把这个指向内存中刚刚创建的新对象的指针return出去,传址赋值给变量。
for of和 for in的区别
for...of 和 for...in 是 JavaScript 中的两种循环语句。
for...of 循环遍历可迭代对象(例如数组)的值。
for...in 循环遍历对象的属性。
因此,for...of 适用于遍历数组中的值,而 for...in 适用于遍历对象的属性。
在使用 for...of 和 for...in 循环时,可以使用 break 和 continue 语句来控制循环的流程。
在使用 for...in 循环时,应注意遍历的是对象的所有可枚举属性,包括它的继承链中的属性。因此,如果对象继承了一些不希望遍历的属性,可以使用 hasOwnProperty 方法来检查该属性是否为对象本身的属性:
for...in 循环的迭代顺序是不确定的,因此如果希望按照特定顺序遍历对象的属性,可以使用 Object.keys 方法将对象的属性名组成的数组传递给 for...of 循环。
什么是同步异步
在 JavaScript 中,同步和异步指的是程序的执行方式。
JavaScript 是单线程语言,意味着它只能在一个时间点上执行一个任务。如果遇到耗时较长或涉及网络通信的任务,如果使用同步方式执行,程序就会停止执行,直到任务完成,这显然不是理想的方案。
因此,JavaScript 中的异步编程就应运而生。异步编程的核心思想是使用回调函数或事件机制,将耗时较长的任务交给浏览器或系统执行,JavaScript 程序在等待任务完成时继续执行,在任务完成时调用回调函数或触发事件通知程序进行下一步操作。
例如,在 JavaScript 中使用 XMLHttpRequest 对象发送网络请求时,可以设置回调函数或事件处理器来处理服务器响应,这样 JavaScript 程序就可以在等待服务器响应时继续执行,在服务器响应到达时再调用回调函数或触发事件进行处理。

常见的异步方式:
①定时器,setTimeout,setInterval
②接口调用,axios.get() , axios.post(), axios({}),node中的 readFile(),writeFile()
③事件函数, dom.addEventLister("click",function(){})


深浅拷贝
深拷贝和浅拷贝是指在复制对象时,复制的方式不同。
浅拷贝只是复制对象的引用,并不会复制对象本身。如果对象是基本类型,则复制的是值本身;如果对象是引用类型,则复制的是指向对象内存地址的指针。因此,如果对象是引用类型,则拷贝后的对象和原对象指向的是同一块内存,任意一方的修改都会影响另一方。
深拷贝则是完全复制了对象本身,包括对象内部的所有属性和方法。深拷贝后的对象和原对象没有任何关联,对其中一方的修改不会影响另一方。
在 JavaScript 中,可以使用以下方法实现深拷贝:
1使用 JSON 序列化和反序列化。这种方法适用于简单对象和数组,但不能复制函数、正则表达式、日期等对象。

COPY CODE

DEEPCOPY (OB J)

FUNCTION

RETURN JSON. PARSE(JSON.STRINGIFY(OBJ);


使用递归算法。这种方法可以复制任意类型的对象

COPY CODE

FUNCTION DEEPCOPY(OBJ) (

OBJ - NULL)

OB JECT'

IF (TYPEOF OBJ !

RETURN OBJ;

LET COPY - ARRAY. ISARRAY(OBJ) ? [] : {;

FOR (LET KEY IN OBJ) (

COPY[KEY] - DEEPCOPY(OBJ[KEY]);

RETURN COPY;


另外,JavaScript 中还有一种浅拷贝的方法:使用 Object.assign() 函数。这个函数可以把一个或多个源对象的所有可枚举属性复制到目标对象中。

COPY CODE

LET OBJ { A: 1, B: 2};

LET COPY - OBJECT.ASSIGN(), OB)

OBJ);


这种方法只能复制对象的属性,对于对象的方法和属性值为对象的属性,不会进行复制。

深拷贝 为什么他能做到互不影响
深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。参考:https://www.jianshu.com/p/21403175f922
事件代理和场景
名称:事件代理,又叫事件委托。
本质:利用事件冒泡,只制定一个事件处理程序,就可以管理某一类型的所有事件。

优点:
1无须监听每个元素的事件,减少事件处理函数。
2.元素增减,不会影响监听事件。
3JavaScript和DOM节点之间的关联减少,避免因循环引用引起的内存泄漏。

场景:
1存在大量相同事件,子节点频繁添加或移除。
2🔔可以举例React中的合成事件。
记得Object.defineProperty有几个参数吗?知道每个参数做了什么?
Object.defineProperty 方法有三个参数:
1obj: 要在其上定义属性的对象。
2prop: 要定义或修改的属性的名称。
3descriptor: 将被定义或修改的属性描述符。
descriptor 可以是以下属性的对象:
value: 属性的值。可以是任何有效的 JavaScript 值(数字,对象,函数等)。默认值为 undefined。
writable: 如果为 true,则可以通过赋值运算符更改属性的值。默认值为 false。
enumerable: 如果为 true,则可以枚举该属性。默认值为 false。
configurable: 如果为 true,则可以通过 delete 运算符删除该属性,以及修改属性的特性。默认值为 false。
例如,下面的代码使用 Object.defineProperty 方法在对象 obj 上定义了一个名为 foo 的属性,该属性的值为 'bar',可写,可枚举,可配置:
除了上述属性,descriptor 对象还可以包含两个函数:
get: 当读取属性值时调用的函数。这个函数没有参数,并返回属性值。
set: 当写入属性值时调用的函数。这个函数有一个参数,表示要写入的新值。
例如,下面的代码使用 Object.defineProperty 方法在对象 obj 上定义了一个名为 foo 的属性,该属性的值由 get 和 set 函数控制:
请注意,如果同时定义了 value、writable 和 get、set 函数,则会抛出错误。你只能选择定义属性的值或访问器函数。
纯函数是什么
纯函数就是一个函数,只不过具有一些特点,你可能平时开发中都有用到,只是没有意识到这是一个纯函数。
纯函数(Prue function)具有以下特点:
1纯函数每一次调用时传入同样的参数,返回的都是同样的结果;它不会改变参数的值,也不会改变外部变量的值;它不会依赖于外部的变量,仅依赖于你传入的参数;
2纯函数没有其他副作用(side effect)
3如果你每次传入的参数一样,但是返回的结果不一样,则不是一个纯函数
这是一个纯函数:

这不是一个纯函数:
怎么创建一个文档碎片
【必答】在JS中我们主要是通过document.createDocumentFragment()方法来创建一个文档碎片
【选答】文档碎片有一个很重要的特点:当需要添加多个dom元素时,如果先将这些元素添加到DocumentFragment(文档碎片)中,再统一将DocumentFragment(文档碎片)添加到页面,会减少页面渲染dom的次数,效率会明显提升。Vue的底层就充分使用了文档碎片来提升页面渲染性能。
工具类(git&webpack)
git命令、git的工作区有哪些
Git 工作区包括以下几个部分:
1本地仓库:本地仓库是 Git 管理的文件的集合,它存储在本地磁盘上。
2工作目录:工作目录是用来修改和查看文件的地方。它包含了本地仓库中的文件的实际内容,也就是我们平常使用的文件。
3暂存区(Staging Area):暂存区是用来准备下一次提交的地方。当我们在工作目录中修改了文件,如果想要把这些修改提交到本地仓库,就需要先把修改的文件添加到暂存区。
4版本库(Repository):版本库是用来存储所有提交的地方。它包含了所有的提交历史,以及每次提交时本地仓库的快照。
在 Git 中,我们通常会在工作目录中修改文件,然后使用 git add 命令将修改的文件添加到暂存区,再使用 git commit 命令将暂存区中的修改提交到本地仓库。本地仓库中的文件就会更新为最新的版本,同时也会把提交记录存储到版本库中。

git命令:下图中标记了红色点是常用的命令,尽量多的说出来

GIT常用命令速查表

默认开发分支

HEAD :默认开发分支

MASTER

默认远程版本库

HEAD:HEAD 的父提交

ORIGIN

分支与标签

创建版本库

#克隆远程版本库

$ GIT CLONE <URL>

#显示所有本地分支

$ GIT BRANCH

$ GIT CHECKOUT<BRANCH/TAG>

#切换到指定分支或标签

#初始化本地版本库

GITINIT

$ GIT BRANCH <NEW-BRANCH>

#创建新分支

修改和提交

#删除本地分支

$ GIT BRANCH-D <BRANCH>

#列出所有本地标签

$ GIT TAG

#查看状态

STATUS

GIT G

中华$$$$中

#基于最新提交创建标签

$ GIT TAG <TAGNAME>

GIT DIFF

#查看变更内容

#删除标签

GIT TAG <TAGNAME>

#跟踪所有改动过的文件

GITADD

#跟踪指定的文件

GIT ADD <FILE>

合并与衍合

GIT MV <OLD><NEW>

#文件改名

#合并指定分支到当前分支

#删除文件

GIT MERGE<BRANCH>

GIT  RM <FILE>

#停止跟踪文件但不删除

#衍合指定分支到当前分支

$ GIT REBASE<BRANCH>

GIT RM --CACHED <FILE>

$GIT COMMIT-M "COMMIT MESSAGE"

#提交所有更新过的文件

远程操作

#修改最后一次提交

$ GIT COMMIT--AMEND

#查看远程版本库信息

$ GIT REMOTE-V

#查看指定远程版本库信息

$ GIT REMOTE SHOW <REMOTE>

查看提交历史

$ GIT REMOTE ADD <REMOTE><URL>

#查看提交历史

$GIT LOG

#添加远程版本库

中守守

D

#查看指定文件的提交历史

GIT LOG -P <FILE>

#从远程库获取代码

$ GIT FETCH <REMOTE>

$ GIT PULL <REMOTE> <BRANCH>

GIT BLAME <FILE>

#以列表方式查看指定文件

#下载代码及快速合并

0 $GIT PUSH <REMOTE><BRANCH> #上传代码及快速合并

的提交历史

$ GIT PUSH <REMOTE>

C

:<BRANCH/TAG-NAME>

撤消

#删除远程分支或标签

#上传所有标签

$ GIT PUSH --TAGS

#撤消工作目录中所有未提交

HARD HEAD

GIT

RESET

文件的修改内容

#撤消指定的未提交文件的修

$ GIT CHECKOUT

<FILE>

HEAD

改内容

#撤消指定的提交

GIT R

T REVERT <COMMIT>


webpack版本号
2015,webpack1支持CMD和AMD,同时拥有丰富的plugin和loader,webpack逐渐得到广泛应用。
2016,webpack2相对于webpack1最大的改进就是支持ES Module,可以直接分析ES Module之间的依赖关系
2017,webpack3相对于webpack2,过渡相对平稳,但是新的特性大都围绕ES Module提出
2018年,webpack4,可以零配置运行,打包速度比之前提高了90%
2020年,webpack5,对构建速度做了突破性的改进,开启文件缓存之后,再次构建,速度提升明显

网络类问题
http有了解过么 展开说说?
HTTP(Hypertext Transfer Protocol)是一种基于请求/响应模型的、无状态的协议,用于在网络中传输超文本文档。
HTTP通常用于在万维网上传输超文本文档(HTML),但是它也可以用于传输其他类型的文档,例如XML和JSON。
HTTP协议使用端口号80和443。端口号80是HTTP协议的默认端口,端口号443是HTTPS协议的默认端口。
HTTP协议包括五个方法,分别是GET、POST、PUT、DELETE和HEAD。每个方法都有其特定用途。
GET方法用于获取指定资源的信息。
POST方法用于向指定资源提交数据进行处理(例如提交表单或上传文件)。
PUT方法用于更新指定资源的信息。
DELETE方法用于删除指定资源。 HEAD方法用于获取指定资源的信息,但是不返回资源的实际内容。
HTTP协议使用状态码表示请求的结果。常见的状态码包括200 OK(请求成功)、301 Moved Permanently(永久性重定向)、404 Not Found(未找到)和500 Internal Server Error(服务器内部错误)。

[(建议精读)HTTP灵魂之问,巩固你的 HTTP 知识体系]
http握手总共有几次 分别是什么
HTTP是一种应用层协议,用于在计算机之间传输数据。它使用 TCP 协议来保证数据的可靠传输。
TCP 协议使用了三次握手来建立连接。三次握手过程如下:
1客户端发送一个连接请求给服务器,包含了一个随机的序列号。
2服务器收到连接请求后,会返回一个应答报文,包含了随机的序列号以及一个确认号。
3客户端收到服务器的应答后,会再次发送一个应答报文给服务器,其中包含服务器发送的随机序列号和确认号。
这样,服务器和客户端就完成了三次握手,建立了一条可信的连接。在这条连接中,客户端和服务器就可以交换数据。
三次握手的目的是为了保证数据的可靠传输。在建立连接之前,客户端和服务器都会发送一些控制报文来确认对方的存在,并且确定序列号和确认号,以便在之后的数据传输过程中使用。这样可以避免数据包丢失或重复出现,保证了数据的可靠传输。
[关于三次握手与四次挥手面试官想考我们什么]
一个页面从输入 URL 到页面加载显示完成的过程:
当用户在浏览器中输入 URL 并按下回车时,浏览器会向服务器发送 HTTP 请求,请求指定的资源。服务器收到请求后,会根据请求的 URL 返回对应的资源,这通常是一个 HTML 文件。浏览器收到服务器返回的 HTML 文件后,会开始解析 HTML 代码,并在浏览器中构建 DOM (Document Object Model) 树。
在解析过程中,浏览器会根据 HTML 中的标签引用的外部资源(如 CSS、JavaScript 文件)发送请求,加载这些资源。浏览器会等待所有这些资源都加载完成,然后再渲染页面。
在渲染过程中,浏览器会使用构建的 DOM 树和加载的 CSS 文件来计算每个元素的布局,并将这些元素绘制到浏览器窗口中。如果 HTML 中还包含 JavaScript 代码,浏览器会执行这些代码,可能会修改 DOM 结构或者添加新的内容。
当所有的 HTML 代码解析完成,所有的资源加载完成,所有的 JavaScript 代码执行完成后,页面就会显示完成。
常见的 HTTP 状态码:
HTTP 状态码是 HTTP 协议的一部分,用于表示 HTTP 请求的结果。它们通常是服务器向浏览器发送的 3 位数字代码。下面是一些常见的 HTTP 状态码:
200 OK:服务器成功处理了请求。这是最常见的 HTTP 状态码,表示请求已成功。
301 Moved Permanently:永久性重定向。请求的资源已被永久地移动到新位置,并且将来的所有请求都应该使用新的 URI。
302 Found:临时性重定向。请求的资源临时从不同的 URI 响应请求。注意,在 HTTP/1.0 中,这个状态码也被用于重定向。
400 Bad Request:服务器无法理解请求。这通常是因为客户端请求中的语法错误。
401 Unauthorized:请求要求身份验证。客户端必须先使用授权标头发送身份验证信息。
403 Forbidden:服务器拒绝了请求。这通常是因为服务器上的文件或目录的权限设置导致的。
404 Not Found:服务器找不到请求的资源。这是最常见的 HTTP 错误代码,表示服务器无法找到请求的网页。
500 Internal Server Error:服务器内部错误。这表示服务器遇到了意料不到的情况,导致了它无法处理请求。这可能是由于服务器上的代码错误或者其他原因造成的。
以上这些只是一些常见的 HTTP 状态码,实际上 HTTP 协议中定义了许多其他状态码。例如,HTTP 状态码 100 表示继续(Continue),表示客户端应该继续其请求;HTTP 状态码 204 表示无内容(No Content),表示服务器已成功处理请求,但是没有返回任何内容。
有关 HTTP 状态码的更多信息,可以参考 HTTP 协议的相关文档或者百度搜索。
33、三次握手和四次挥手:
三次握手是用于在两台计算机之间建立网络连接。它包括以下三个步骤:
1客户端向服务器发送连接请求。
2服务器向客户端发送确认消息,表明服务器已准备好接受连接。
3客户端向服务器发送确认消息,表明客户端已收到服务器的确认消息,并准备好开始数据传输。
四次挥手是用于在两台计算机之间终止网络连接。它包括以下四个步骤:
1客户端向服务器发送断开连接请求。
2服务器向客户端发送确认消息,表明服务器已收到断开连接请求。
3服务器向客户端发送断开连接请求。
4客户端向服务器发送确认消息,表明客户端已收到服务器的断开连接请求。
HTTP和HTTPS区别:
HTTP (HyperText Transfer Protocol) 和 HTTPS (HTTP Secure) 都是用于在计算机之间传输数据的协议。但是,HTTPS在传输数据时使用了安全套接层 (SSL) 或者传输层安全 (TLS) 协议来加密数据,以防止第三方拦截或窃取数据。
主要区别如下:
1安全性:HTTPS 在传输过程中使用了加密技术,而 HTTP 没有。这意味着,使用 HTTPS 可以保护数据不被窃取或篡改。
2证书:使用 HTTPS 需要在服务器端安装 SSL 证书。这个证书可以用来验证服务器的身份,确保用户访问的是真实的网站。
3端口号:HTTP 使用的是 80 端口,而 HTTPS 使用的是 443 端口。
4URL:HTTP 的 URL 以 "http://" 开头,而 HTTPS 的 URL 以 "https://" 开头。
总的来说,使用 HTTPS 可以提供更好的安全性,特别是在处理敏感信息或者在公共网络上使用时。
Vue2框架
MVVM的理解:
MVVM是一种设计模式,用于将用户界面(UI)与业务逻辑分离。这样可以使 UI 的开发与业务逻辑的开发相互独立,更容易维护和扩展。
MVVM 的名称来自于三个部分:
Model(模型):表示应用程序中的数据模型。它代表着应用程序中的业务逻辑和状态。
View(视图):表示应用程序的用户界面。它是用户与应用程序交互的方式。
ViewModel(视图模型):是一个桥梁,将模型与视图连接在一起。它提供了视图所需的数据和命令,并将用户的输入转换为模型的操作。
通常,ViewModel 通过数据绑定将数据提供给视图,并使用命令处理视图中的用户输入。这样,视图可以直接与 ViewModel 交互,而无需与模型直接交互。这使得视图的开发和模型的开发相互独立,并且可以更轻松地测试和维护应用程序。
MVVM 模式的优点包括:
将 UI 和业务逻辑分离,使得 UI 和业务逻辑的开发相互独立。
提供了更好的测试支持,因为视图和业务逻辑是分离的,所以可以更轻松地对它们进行单元测试。
易于维护和扩展,因为业务逻辑和 UI 分离,所以可以更轻松地更改一个而不会影响另一个。
MVVM 模式也有一些缺点,包括:
可能会使代码变得较复杂,因为需要编写数据绑定和命令的代码。
可能需要使用特定的框架才能实现 MVVM 模式,例如 Vue 或 Angular。
总的来说,MVVM 是一种有用的设计模式,可以帮助你将用户界面与业务逻辑分离,从而使应用程序更易于维护和扩展。
插槽:
在Vue2中,插槽(Slot)是一种将父组件中的内容传递给子组件的机制。通过插槽,父组件可以向子组件传递HTML代码、组件实例或其他任意内容,并在子组件中使用。
插槽分为两种类型:具名插槽和默认插槽。
具名插槽可以让父组件传递多个插槽到子组件中,并在子组件中通过插槽名称进行访问。
默认插槽是没有指定名称的插槽,当父组件没有传递具名插槽时,子组件就会使用默认插槽中的内容。
通过使用插槽,Vue2中的组件可以更加灵活地处理内容,可以在子组件中动态渲染内容,实现更加复杂的UI效果。
68、vue组件中data为什么必须是一个函数:
在 Vue.js 中,组件的 data 选项必须是一个函数,这是因为每个组件实例都应该有自己的状态,如果 data 不是一个函数,那么所有实例将共享同一个数据对象,这会导致组件之间的状态混乱。
举个例子,假设你有一个组件 A 和组件 B,如果你把 data 写成这样:
那么组件 A 和组件 B 中的 message 都是同一个值,如果在组件 A 中修改了 message,那么组件 B 中的 message 也会改变。这显然不是你想要的结果。
因此,Vue.js 要求 data 选项必须是一个函数,这样每个组件实例都可以有自己的 data 对象。你可以这样写:
这样就能保证每个组件实例都有自己的 data 对象,组件之间的状态就不会混乱了。
35、Vue 数据双向绑定的原理:
在 Vue.js 中,数据双向绑定是通过使用观察者模式来实现的。观察者模式是软件设计模式的一种,它允许对象之间的一对多关系。在这种关系中,一个对象(称为发布者)维护一组依赖于它的对象(称为订阅者),并在其状态更改时通知所有订阅者。
在 Vue.js 中,发布者是 Vue 实例,订阅者是观察者。当 Vue 实例的数据发生变化时,Vue 会通知观察者,观察者会更新视图。这样,当用户在视图中进行操作时,Vue 会更新数据,并通知观察者更新视图。
为了实现数据双向绑定,Vue 使用了一种叫做劫持的技术。劫持就是在数据变化时捕获数据并通知观察者。Vue 实现劫持的方法是使用 Object.defineProperty() 函数,该函数允许在对象的属性被访问或修改时进行拦截。
当 Vue 实例被创建时,它会在内部遍历所有数据并使用 Object.defineProperty() 函数为每个属性添加 getter 和 setter。这样,当数据被访问或修改时,Vue 就可以捕获数据并通知观察者。
例如,当你在 Vue 实例中声明一个属性 message:
Vue 会使用 Object.defineProperty() 函数为 message 属性添加 getter 和 setter,这样在访问或修改 message 属性时,Vue 就可以捕获数据并通知观察者。
当视图中的数据改变时,Vue 会使用 setter 通知观察者。观察者会更新视图,而用户在视图中的操作会使用 getter 更新数据。这样,数据和视图之间就形成了双向绑定。
自己举一个使用vuex的完整过程
使用 Vuex 的过程大致如下:
1安装 Vuex:使用 npm 或 yarn 安装 Vuex。
2创建 store:创建一个 store.js 文件,并在文件中定义 store 的状态、getters、mutations 和 actions。
3在入口文件中加载 store:在应用的入口文件中引入 store.js 文件,并将 store 实例作为参数传递给 new Vue()。
在组件中使用 Vuex:在组件中使用 $store 访问 store 中的状态、getters、mutations 和 actions。
以上就是使用 Vuex 的完整过程。
递归
递归是一种编程技术,允许函数调用自身。这种技术可用于解决一些复杂的问题,并且通常比循环更简洁易懂。
举个例子,假设你想要计算某个数的阶乘。阶乘是一个数的所有自然数的乘积,如5的阶乘为5 * 4 * 3 * 2 * 1。
你可以使用递归来实现这个函数,具体方法是:
如果这个数小于等于1,则返回1。
否则,返回这个数乘上它的(n-1)的阶乘。
这样,每次调用函数时,它就会调用自身,直到数字小于等于1,然后开始返回结果。
递归还有很多其他应用场景,例如:
计算斐波那契数列的某一项。
在数据结构中,例如二叉树或链表,递归可以用来遍历整个数据结构。
在排序算法中,递归可以用来实现快速排序或归并排序。
总的来说,递归是一种非常有用的编程技术,能帮助你解决一些复杂的问题。但同时,也要注意递归程序可能会占用大量的内存,因此要谨慎使用。
v-model实现的原理
在 Vue.js 中,v-model 指令是一种语法糖,它的作用是为表单元素绑定双向数据绑定。这意味着当用户输入表单元素时,它会更新 Vue 实例的数据,同时也会将 Vue 实例中的数据反映到表单元素上。
例如,如果你想要在 Vue 实例中绑定一个输入框的值,你可以使用 v-model 指令:

实现原理
v-model 指令的实现原理是基于计算属性和事件绑定。它会将表单元素的 value 属性绑定到一个计算属性上,并且在计算属性的 setter 中触发 input 事件来更新 Vue 实例中的数据。
例如,上面的代码实际上等价于:
这样,当用户在输入框中输入文本时,输入框的 value 属性会被更新
单页面应用
单页面应用(Single-Page Application,简称 SPA)是一种架构方式,它在一个单独的网页中加载所有的资源,并使用 JavaScript 在客户端渲染用户界面,而不是通过服务器进行渲染。这意味着,当用户在 SPA 应用中导航到不同的页面时,不会发生实际的页面跳转,而是在当前页面内使用 JavaScript 更新内容。这使得 SPA 应用的体验非常流畅,因为不会有页面加载的延迟。
与传统的多页面应用相比,单页面应用具有许多优势,包括:
快速响应:由于不需要重新加载页面,因此 SPA 应用可以快速响应用户的操作。
减少服务器负载:由于大部分的处理都是在客户端进行的,因此 SPA 应用可以减少服务器的负载。
更好的用户体验:由于 SPA 应用的页面切换非常流畅,因此它可以提供更好的用户体验。
然而,单页面应用也有一些缺点,包括:
较难调试:由于 SPA 应用的代码都在客户端运行,因此调试可能会更加困难。
SEO 难度较大:对于单页面应用,搜索引擎爬虫可能无法正常抓取页面内容,因此 SPA 应用的 SEO 较为困难。为了解决这个问题,可以使用服务端渲染(Server-Side Rendering,简称 SSR)技术,在服务器端渲染 SPA 应用的内容,使得爬虫可以正常抓取页面内容。
总的来说,单页面应用是一种有效的架构方式,它可以提供流畅的用户体验,但在 SEO 和离线使用方面存在一定的困难。
vue的理解?
Vue.js 是一个渐进式的 JavaScript 框架,旨在通过尽可能简单的 API 实现响应式数据绑定和组合的视图组件。
Vue.js 的核心是一个叫做 Vue 实例的 JavaScript 对象,该对象用于控制一个 HTML 页面中的一个区域,称为“视图”。Vue 实例可以通过声明式模板或使用 JavaScript 代码动态渲染视图。
Vue.js 的响应式系统使得在模型数据变化时,视图会自动更新。这意味着,你可以在不手动操作 DOM 的情况下改变视图。Vue.js 还提供了许多其他功能,如组件系统、路由、状态管理等,可以帮助你构建复杂的单页应用。
总的来说,Vue.js 是一个轻量级的、易于使用的前端框架,可以帮助你快速构建响应式的 Web 应用。
vue.js中如何监听路由信息的改变
1通过watch监听
2通过路由钩子函数监听

watch监听

通过路由钩子函数监听
nexttick的理解
nextTick 是 Vue.js 中一个用来在下一个事件循环中调用回调函数的方法。这个方法通常用在等待数据或 DOM 元素更新之后执行一些代码的情况下。
举个例子,假设你有一个组件,它的模板中使用了一个计算属性 fullName,该计算属性由组件中的 firstName 和 lastName 两个数据项拼接而成:
假设你想要在更新 firstName 和 lastName 后执行一些代码,但你发现 Vue 的计算属性是同步的,所以你无法在计算属性更新之后立即执行代码。这时你就可以使用 nextTick 方法:
这样你就可以在计算属性更新之后执行代码了。
你可能会在组件的生命周期钩子函数 created 中使用 nextTick,因为在该钩子函数中组件的模板还没有被渲染,但是你想要在模板渲染之后执行一些代码:

vue给对象添加新属性界面不刷新?
原因:Vue 不允许在已经创建的实例上,动态添加新的响应式属性;
三种解决办法:
1使用Vue.set( target , key , value)
2使用$fourceUpdate强制刷新
3克隆新对象,如this.persons ={...this.persons}, this.persons = Object.assign({}, this.persons)
之前有用到Vue 2.几的版本
在命令面板中输入:npm view vue versions 就可以查看到所有可用的vue版本
截止到2022年7月30日
vue2最新的版本是:2.7.8
vue3最新的版本是:3.2.37

vue中key的原理
在 Vue.js 中,当使用 v-for 指令渲染一个列表的时候,Vue.js 强制要求使用 key 属性来提高性能。这个 key 属性是 Vue.js 内部使用的,它并不会对你的应用造成任何影响。
在 Vue.js 内部,使用 key 属性可以帮助 Vue.js 识别列表中的每个元素。这样 Vue.js 就可以更快地更新列表中的元素,因为它可以直接找到要更新的元素,而不是遍历整个列表来寻找需要更新的元素。
使用 key 属性的方法是在每个 v-for 指令的模板中给每个元素添加一个唯一的 key 属性,如下所示:
在上面的例子中,Vue.js 会使用每个元素的 id 属性作为 key 属性。你可以使用任何唯一的值作为 key 属性,只要它能唯一标识列表中的每个元素即可。
总的来说,使用 key 属性可以帮助 Vue.js 更快地更新列表中的元素,提高应用的性能。
Vue 组件通讯:
父传子:子组件定义props属性接收
子传父:子组件中使用this.$emit方法
兄弟传值:事件总线,$on方法
父传孙:provide和inject方式
兄弟组件的传值
1使用eventBus,跨组件通信
2借鉴React,使用状态提升
3使用Vuex
自定义指令的使用以及生命周期/钩子函数:
分类:全局自定义指令,局部自定义指令
全局自定义指令:

局部自定义指令:

生命周期/钩子函数:
inserted:被绑定元素插入父节点时调用
bind:只调用一次,指令第一次被绑定到元素时
update:元素本身更新时触发
componentUpdate:组件和子组件更新时触发
unbind:指令被移除时触发
每个钩子函数中都有el和binding参数,而componentUpdate钩子中还暴露一个oldVal,用以区分旧值和新值
el:绑定元素
binding:是一个参数对象,一般我们会用到其中的value值,用于src的属性值
说5个vue的指令
1v-bind:绑定属性
2v-if 、v-show:条件渲染
3v-for: 列表渲染
4v-model:双向绑定
5v-html:解析html字符串
6v-on:绑定事件
路由懒加载:
在 Vue.js 中,懒加载可以帮助你减小应用的初始加载大小,并在路由被访问时再加载对应的组件。这可以通过使用 Vue 的异步组件和 Webpack 的代码分割功能来实现。
首先,你需要将你的组件定义为异步组件,这意味着它不是立即加载的,而是在被访问时才加载。你可以使用 Vue 的 component 属性提供一个工厂函数来实现这一点,例如:
接下来,你可以在路由配置中使用这个异步组件。例如:
这样,当你访问 /some-route 时,组件 some-component.vue 就会被异步加载,而不是在应用初始加载时一并加载。
注意,上面的例子假设你已经使用了 Webpack 和 vue-loader,并且在 Webpack 配置中启用了代码分割功能。这样,Webpack 就会将组件分割成独立的包,并在被访问时动态加载。
44、Vuex核心属性:
state:定义需要管理的数据
getters:state派生出来的数据,相当于state的计算属性
mutation:里面定义的是同步的更新数据方法,每个方法里都有两个参数,一个是state,一个是payload,通过store.commit调用
action:里面定义的是异步的方法,每个方法里面有两个参数,一个是store,一个是payload,通过store.dispatch调用,在actions里也可以提交mutation,通过store.commit
module:将vuex模块化,可以让每一个模块拥有自己的state、mutation、action、getters,结构清晰,方便管理

46、路由模式:
hash模式:
浏览器中符号是“#”,#以及#后面的字符称之为 hash,又叫前端路由
用 window.location.hash 读取
hash 虽然在 URL 中,但不被包括在 HTTP 请求中
hash 改变会触发 hashchange 事件
hash发生变化的url都会被浏览器记录下来,从而浏览器的前进后退都可以用
history模式:
history 采用 HTML5 的新特性
history 模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中
它也有个问题:不怕前进,不怕后退,就怕刷新(如果后端没有准备的话,会分分钟刷出一个404来),因为刷新是实实在在地去请求服务器的
48、路由之间跳转方式:
四种方式:
router-link搭配to属性,在模板中使用
push()跳转到指定页面
replace()跳转到指定页面,但是没有历史记录跳不回去
go(N)N可以为正数也可以为负数,正数是向前跳转,负数是向后跳转

49、如何封装组件:
原因:封装组件可以提升项目开发效率,把页面抽象成多个相对独立的模块,复用性高
步骤:
创建一个组件
Vue.component注册组件
子组件需要数据,可以在props中接受定义
而子组件修改好数据后,想把数据传递给父组件,可以采用emit方法

v-show和v-if的区别
作用:添加渲染,切换显示与隐藏
不同:v-if会移除dom或组件树,v-show则只是通过样式隐藏
场景:
1v-if:切换不频繁、敏感数据的隐藏(如权限按钮)
2v-show:切换频繁的场景

v-for和v-if为什么不能一起使用
【回答此句-良好】在vue2中v-for优先级高于v-if,如果二者放在同一级标签里面,每次都要先循环,再判断,消耗很多性能。
【回答此句-优秀】对于同一组数据来说,如果我们要先判断再渲染,可以在外层包装一个div,使用v-if做一次判断即可。Vue3解决了这个问题,将v-if的优先级调整为高于v-for了。

说说vue的生命周期
好的,这个问题其实是这样的:
【必须回答】Vue中的生命周期本质上就是按顺序固定执行一个个的钩子函数,我们开发者可以在每个函数中写入特定代码来实现我们需要的功能

例如我们常用的ajax请求通常就放在created或者mounted中

------回答标准:以下分类能说出几个就是几个,这样就是到了回答良好的标准,但是不能一个都说不出来,-----

vue2的生命周期从分类上来看有如下几种情况:
1 组件创建和挂载相关的钩子函数有
abeforeCreate
bcreated
cbeforeMount
dmounted
2 组件更新相关的钩子函数有
abeforeUpdate
bupdated
3 组件销毁相关的钩子函数有
abeforeDestroy
bdestroyed

【以下如果能回答出来是超过面试官预期的,更加优秀】
1还有一个组件缓存激活相关的钩子函数是:activated和deactivated,这两个要配合keep-alive 缓存的组件一起使用
2vue3总体来说什么周期执行顺序是一样的,不同点在于beforeCreate和created都被setup函数替代了
参考链接:https://cn.vuejs.org/v2/api/#activated

Vue组件之间的传递方式
Vue组件之间数据传递的几种方式:
[回答第1,2条-合格,因为是常用的]
1父组件向子组件传递数据,使用props属性;子组件向父组件中传递数据,在子组件中使用$emit派发事件,父组件中使用v-on监听事件。缺点:组件嵌套层次多的话,传递数据比较麻烦。
2通过Vuex,实现多个组件进行数据共享,推荐使用这种方式进行项目中各组件间的数据传递。
[如果还能将第3条回答出-良好]
3通过事件总线(eventbus)的方式,可以实现任意两个组件间进行数据传递;缺点:不支持响应式,这个概念是vue1.0版本中的,现在已经废弃
[如果还能将第4,5条回答出-优秀]
4祖先组件通过依赖注入(inject/provide)的方式,向其所有子孙后代传递数据;缺点:无法监听数据修改的来源,不支持响应式。
5通过属性parent/$children/ref,访问根组件、父级组件、子组件中的数据;缺点:要求组件之间要有传递性。

vue-router的钩子函数
钩子函数有三种:
1【必答-合格】全局守卫:beforeEach(全局前置守卫),beforeResolve(全局解析守卫) ,afterEach(全局后置钩子)
2【选答-良好】路由独享守卫:可以直接在路由配置上定义 beforeEnter 守卫
3【选答-优秀】组件内的守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

Pinia和vuex的区别,vuex的不足
Vuex和Pinia都是vue.js的状态管理工具,Vuex是vue2使用,而在vue3推荐了Pinia,主要有以下几点区别:
Pinia没有mutation,他只有state,getters,action【同步、异步】使用它来修改state数据
Pinia语法上比vuex更容易理解和使用,灵活。
Pinia没有modules配置,每一个独立的仓库都是definStore生成出来的、
Pinia的state是一个在函数中返回的对象,和vue组件中的data编写方式差不多
vuex的不足 :
Pinia和Vuex都是非常好用的数据管理工具,在某些情况下,使用Pinia的web应用程序会比使用Vuex更快,这种性能的提升可以归因于Pinia的极轻的重量,Pinia体积约1KB。

vite和wabpack的区别
【必答】 webpack会先打包,然后启动开发服务器,请求服务器时直接给予打包结果,当项目文件大的时候会出现打包时间长的问题启动服务器缓慢的问题;vite是直接启动开发服务器,请求哪个模块再对该模块进行实时编译,所以启动速度快,感受好,启动服务器时的优势相对明显
【必答】在热更新方面,当改动了一个模块后,仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
【选答】当需要打包到生产环境时,vite使用传统的rollup进行打包,因此,vite的主要优势在开发阶段。另外,由于vite利用的是ES Module,因此在代码中不可以使用CommonJS

TS的作用、TS代码可以在浏览器解析吗
【必答】ts相对于js而言主要增加了一个类型检测系统,我们大多数也是用它来帮助我们更好的开发项目,它多了如下作用:
可以轻松避免在编写代码过程中的类型错误,例如: let num = 10; num ="20" ts会给你实施抛出类型错误,这样能够让我们的代码变得更加规范,减少系统在运行时的错误
使大型、复杂的应用程序源码更易阅读。
【必答】TS代码本身不能在浏览器中解析,它需要基于node的一个typescript编译器来将ts代码编译成js代码,才能在浏览器上运行

vue3和vue2区别
答题技巧:以下4部分内容,挑选出你能够hold得住的去回答即可
1vscode插件和调试工具方面
a代码高亮,语法提示方面:vue2项目主要用Vetur插件,vue3中主要用Volar
b语法片段方面:在vue2中我们一直使用Vue 2 Snippets,在vue3我们推荐使用Vue 3 Snippets,因为它支持vue3的同时完全向前兼容vue2
c在浏览器调试工具方面:vue2版本的chrome devtools不再支持vue3,vue3我们需要单独下载Vue.js devtools beta
2兼容性方面:
avue2 不支持 IE8 及以下版本,因为 Vue2 使用了 IE8 无法模拟的 ECMAScript 5 特性,例如:Object.defineProperty()
bvue3 不支持 IE11 及以下版本。
3语法层面
a在vue2中,我们只要定义在data()方法中的数据就是响应式数据,在vue3中我们可以使用ref和reactive定义的响应式数据
b组合式api:为了让相关代码更紧凑vue3提出了组合式api,组合式api能将同一个逻辑关注点相关代码收集在一起。 组合式api的入口就是setup方法。
c在 vue2 中template不支持多根节点组件,vue3支持了多根节点的组件
4底层实现方面
avue2的响应式使用的是Object.defineProperty()实现的,Vue3使用的Proxy实现的
参考:https://juejin.cn/post/7098575243240800286

webpack有了解过么?
webpack主要是我们做工程化开发的打包工具,它会让你指定一个入口,然后通过这个入口分析出此项目的所有依赖,最终将它们打包合并成一个或者多个js文件。
同时他还有很多插件和loader能帮我们提升开发效率。

服务端渲染和客户端渲染分别是什么?
服务器渲染:
页面渲染的工作都是由服务端来完成的,数据也是由服务端提供的,浏览器只负责展示页面内容
容易被爬虫爬取数据,同时能被搜索引擎搜索到,能在搜索引擎中向用户展示数据

客户端渲染:
页面的渲染工作都是由浏览器来完成的,服务器只是负责提供数据。
客户端渲染能尽早的把页面展示给用户,用户体验好
不容易被爬虫爬取数据,同时也无法被搜索引擎搜索到

Vue3中 setup的作用是什么?为什么Vue3比Vue2在script中多了一个setup这个语法糖?
setup的设计是为了在Vue3中使用组合式api
在Vue2中data、computed、methods、watch 组织逻辑在大多数情况下都有效。然而,当我们的组件变得更大时,我们同一个功能的代码会分散在data、computed、methods、watch,这会导致组件难以阅读和理解而通过setup可以将该部分抽离成函数,让其他开发者就不用关心该部分逻辑了。

script中多了一个setup,主要是为了让我们更加方便的编写代码,在setup函数中编写的属性和方法都需要return,如果在<script setup>中编写可以直接使用而无需return
在 script setup 语法糖中,引入的组件可以自动注册,不需要再通过 components 进行注册,而且无法指定当前组件的名字,会自动以文件名为主,省去了 name 属性。
路由的钩子函数
钩子函数有三种:
1【必答-合格】全局守卫:beforeEach(全局前置守卫),beforeResolve(全局解析守卫) ,afterEach(全局后置钩子)
2【选答-良好】路由独享守卫:可以直接在路由配置上定义 beforeEnter 守卫
3【选答-优秀】组件内的守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
vue-router传参方式有哪些?
3种vue路由传参:
1动态路由-路径拼接传参
a传:this.$router.push({path: `/xxx/${id}`)
b接:this.$route.params.id
2动态路由-params属性传参
a传:this.$router.push({name: 'xxx', params: {id: 值})
b接:this.$route.params.id
3query属性传参
a传:this.$router.push({ name: 'xxx', query: { id: 值 } })
b接:this.$route.query.id
前置路由守卫
路由跳转之前, 会触发的一个函数 叫前置路由守卫
语法:router.beforeEach((to, from, next) => {这里可以写路径的跳转判断/有无token值的情况分析})
作用 : 防止别人猜到网址的hash值后直接跳过登录就可以查看数据
里面的3个参数:
to : 到哪里去
from : 从哪里来
next : 放行函数 next():放行 , next(false):不放行
参考:https://blog.csdn.net/m0_65132206/article/details/125023965
路由传参的方式:
编程式的导航router.push:
字符串:
直接传递路由地址,但是不能传递参数this.$router.push("home")
对象:
命名路由:这种方式传递参数,目标页面刷新会报错this.$router.push({name:"news",params:{userId:123})
查询参数:和 name 配对的式 params,和 path 配对的是 querythis.$router.push({path:"/news',query:{uersId:123})
接收参数:this.$route.query
声明式的导航:
字符串:<router-link to:"news"></router-link>
命名路由:<router-link :to:"{name:'news',params:{userid:1111}}"></route-link>
查询参数:<router-link :to="{path:'/news',query:{userId:1111}}"></router-link>
53、 vue-router 动态路由:
场景:把某种模式匹配到的所有路由,全都映射到同个组件
解决办法:以在 vue-router 的路由路径中使用动态路径参数
使用 :开头
在路径中最后使用 ?传参

计算属性与watch的区别
computed是用来计算出来一个值的,这个值调用的时候不需要加括号,会根据依赖进行缓存,依赖不变,computed的值不会重新计算
watch是来监听的,有2个选项
1immediate:表示是否要在第一次渲染的时候执行这个函数
2deep:如果我们监听一个对象,那么我们是否要看这个对象里面属性的变化
如果某个属性变化了,就去执行一个函数

watch的深度监听在哪种场景下使用
使用deep: true解决监听不到对象属性变化的问题

keep-alive使用时从这个页面跳转到另外一个页面返回后这个数据还存在吗?为什么?
数据还存在,keep-alive 可以缓存页面的数据,在页面回跳的时候不会更新数据;因为activated 在开启keep-alive时页面不会重新渲染 也不会进入生命周期

计算属性绑定数据后,跳转到另一个页面再返回,数据是否还在?为什么?
当计算结果不变时,该函数仅会调用一次,这是computed的缓存功能,合理使用会大大提高代码的运行速度。
页面优化:

v-if和v-for不能连用
更多的情况下,使用v-if代替v-show
要保证key值的唯一
使用组件懒加载或者图片懒加载
防抖和节流的使用
模块按需导入
打包优化
使用cdn加载第三方模块
缓存常用信息
精灵图,base64

55、动态组件:

定义:多个组件使用同一个挂载点,并动态切换
使用:,当控制 componentName 改变时就可以动态切换选择组件
vue-router导航守卫/钩子函数:
定义:又称路由守卫,实时监控路由跳转的过程,在各个过程执行相应的操作
分类:
全局守卫:
全局前置守卫:
全局解析守卫
全局后置守卫
路由独享守卫
组件内守卫:参数或查询的改变并不会触发导航守卫,可以通过使用 beforeRouteUpdate 的组件内守卫

61、拦截器:
作用:
Axios 是一个基于 promise 的 HTTP 库,支持promise所有的API
可以拦截请求和响应
可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
安全性更高
相关配置:
url:请求的服务器地址
method:请求方法
baseURL:基准路径
headers:请求头
parmas:路径参数
做了什么:
请求拦截器:
在请求发送前进行的操作,如:每个请求体里加上token
响应拦截器:
接收到响应后进行的操作,如:服务器返回的登录状态失效,就跳转到登录页
56、webpack :

定义:是一个打包模块化的工具,在webpack中一切文件皆为模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件
作用:由于浏览器对于js中的很多代码不可以直接进行解析读取,这个时候需要先通过 wabpack 把资源进行打包,解析成浏览器可以识别的代码
配置:
入口:指示webpack使用哪个模块作为构建其内部依赖图的开始,默认值是:‘./src/index.js’
出口:告诉webpack在哪里输出它所创建的bundle,以及如何命名这些文件,主要输出文件的默认值是‘./dist/main.js’
mode:配置模式,development(开发环境)、production(生产环境)、none(不使用任何默认优化选项)
loader:自带能力,用于转换某些类型的模块
plugin:打包优化,资源管理,注入环境变量等
流程:
初始化参数
开始编译
确定入口
编译
完成模块编译
输出资源
输出完成
深度侦听在什么情况下使用?立即侦听什么情况下使用?
1.deep(深度侦听):默认情况下,侦听器无法侦听对象的属性值的变化,如果想实现这个效果,则需要添加deep配置为true
2. handler(固定方法触发):因为你要添加deep的配置,所以,侦听器的形式要变更为对象形式,只有对象才能添加其它的配置, 同时侦听函数必须为handler
3. immediate(立即侦听):如果需要默认一进页面就触发一次,添加immediate配置选项为true
参考:https://blog.csdn.net/GZZ__z/article/details/120852612
token失效处理:
第一种方案是:服务器端保存token状态,用户每次操作都会自动推迟token的过期时间,session就是采用这种策略保持token的有效期,但是当前后端分离,单页面的时候,每秒钟的请求发起多次,每次都去刷新一下过期时间会非常消耗性能的;
第二种方案:使用refresh token,避免频繁的刷新token,此时服务端只要在token过期的时候反馈给前端,前端使用refresh token申请一个全新的token继续使用即可
Vue3框架
vite和wabpack的区别
【必答】 webpack会先打包,然后启动开发服务器,请求服务器时直接给予打包结果,当项目文件大的时候会出现打包时间长的问题启动服务器缓慢的问题;vite是直接启动开发服务器,请求哪个模块再对该模块进行实时编译,所以启动速度快,感受好,启动服务器时的优势相对明显
【必答】在热更新方面,当改动了一个模块后,仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
【选答】当需要打包到生产环境时,vite使用传统的rollup进行打包,因此,vite的主要优势在开发阶段。另外,由于vite利用的是ES Module,因此在代码中不可以使用CommonJS
Pinia和vuex的区别,vuex的不足
Vuex和Pinia都是vue.js的状态管理工具,Vuex是vue2使用,而在vue3推荐了Pinia,主要有以下几点区别:
Pinia没有mutation,他只有state,getters,action【同步、异步】使用它来修改state数据
Pinia语法上比vuex更容易理解和使用,灵活。
Pinia没有modules配置,每一个独立的仓库都是definStore生成出来的、
Pinia的state是一个在函数中返回的对象,和vue组件中的data编写方式差不多
vuex的不足 :
Pinia和Vuex都是非常好用的数据管理工具,在某些情况下,使用Pinia的web应用程序会比使用Vuex更快,这种性能的提升可以归因于Pinia的极轻的重量,Pinia体积约1KB。
vue3双向绑定怎么实现
vue3 是通过Proxy实现的数据双向绑定,采用的proxy劫持的是整个对象,相比vue2.0defineProperty,能够监听动态新增的属性,可以监听数组的索引和length属性。
参考:https://blog.csdn.net/m0_49471668/article/details/125180606

Vue3中 setup的作用是什么?为什么Vue3比Vue2在script中多了一个setup这个语法糖?
setup的设计是为了在Vue3中使用组合式api
在Vue2中data、computed、methods、watch 组织逻辑在大多数情况下都有效。然而,当我们的组件变得更大时,我们同一个功能的代码会分散在data、computed、methods、watch,这会导致组件难以阅读和理解而通过setup可以将该部分抽离成函数,让其他开发者就不用关心该部分逻辑了。

script中多了一个setup,主要是为了让我们更加方便的编写代码,在setup函数中编写的属性和方法都需要return,如果在<script setup>中编写可以直接使用而无需return
在 script setup 语法糖中,引入的组件可以自动注册,不需要再通过 components 进行注册,而且无法指定当前组件的名字,会自动以文件名为主,省去了 name 属性。

vue3和vue2区别
答题技巧:以下4部分内容,挑选出你能够hold得住的去回答即可
1vscode插件和调试工具方面
a代码高亮,语法提示方面:vue2项目主要用Vetur插件,vue3中主要用Volar
b语法片段方面:在vue2中我们一直使用Vue 2 Snippets,在vue3我们推荐使用Vue 3 Snippets,因为它支持vue3的同时完全向前兼容vue2
c在浏览器调试工具方面:vue2版本的chrome devtools不再支持vue3,vue3我们需要单独下载Vue.js devtools beta
2兼容性方面:
avue2 不支持 IE8 及以下版本,因为 Vue2 使用了 IE8 无法模拟的 ECMAScript 5 特性,例如:Object.defineProperty()
bvue3 不支持 IE11 及以下版本。
3语法层面
a在vue2中,我们只要定义在data()方法中的数据就是响应式数据,在vue3中我们可以使用ref和reactive定义的响应式数据
b组合式api:为了让相关代码更紧凑vue3提出了组合式api,组合式api能将同一个逻辑关注点相关代码收集在一起。 组合式api的入口就是setup方法。
c在 vue2 中template不支持多根节点组件,vue3支持了多根节点的组件
4底层实现方面
avue2的响应式使用的是Object.defineProperty()实现的,Vue3使用的Proxy实现的
参考:https://juejin.cn/post/7098575243240800286

TypeScript
TS的作用、TS代码可以在浏览器解析吗
【必答】ts相对于js而言主要增加了一个类型检测系统,我们大多数也是用它来帮助我们更好的开发项目,它多了如下作用:
可以轻松避免在编写代码过程中的类型错误,例如: let num = 10; num ="20" ts会给你实施抛出类型错误,这样能够让我们的代码变得更加规范,减少系统在运行时的错误
使大型、复杂的应用程序源码更易阅读。
【必答】TS代码本身不能在浏览器中解析,它需要基于node的一个typescript编译器来将ts代码编译成js代码,才能在浏览器上运行
微信小程序
微信小程序已上线要怎么重构,比如原生做的小程序升级为vue+uinapp框架
使用官方推荐的HBuilderX, github地址:https://github.com/zhangdaren/miniprogram-to-uniapp。该插件十分强大,通过简单的脚本命令,直接将我本地的小程序原生项目,clone生成了一份vue.js的项目。
参考:https://ask.dcloud.net.cn/article/38791

做uniapp商城小程序遇到了什么坑?
参考:
https://blog.csdn.net/qq_42625428/article/details/107060379
之前做uniapp开发的时候有做过多端吗?最多做过几端?
uni-app 是一个使用 Vue.js 开发所有前端应用的开源框架,开发者编写一套代码,可发布到的端有:
1 iOS
2Android
3Web(响应式)
4以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)等多个平台。
根据你了解的情况去回答,我们微信小程序是学过的,如何发布成H5页讲过,这两个端至少可以回答
参考:https://blog.csdn.net/qq_15041931/article/details/121711320
扫码进来,有一条链接,但是我要获取链接里面带的参数,怎么获取?
答:直接在对应的页面中的onLoad生命周期方法中通过options即可获取到,二维码中url传入的参数
uniapp 项目要在不同多端发布那么在开发的时候要考虑哪方面的问题呢?
1多端兼容性问题,
2微信开发文档中的配置问题
uniApp开发一般适合什么项目呢?开发中的项目要怎么能达到uniapp的专业规范呢?
为了实现多端兼容,综合考虑编译速度,运行性能等因素,uni-app约定了如下开发规范:
页面文件遵循Vue单文件组件(SFC)规范
组件标签靠近小程序规范,详见uni-app组件规范
接口能力(JS API)靠近微信小程序规范,但需将前缀wx替换为uni,详见uni-app接口规范
数据绑定及事件处理同Vue.js规范,同时补充了App及页面的生命周期
为兼容多端运行,建议使用flex布局进行开发
uniapp 项目要在不同多端发布那么在开发的时候要考虑哪方面的问题呢?
1多端兼容性问题,
2微信开发文档中的配置问题
uniApp开发一般适合什么项目呢?开发中的项目要怎么能达到uniapp的专业规范呢?
为了实现多端兼容,综合考虑编译速度,运行性能等因素,uni-app约定了如下开发规范:
页面文件遵循Vue单文件组件(SFC)规范
组件标签靠近小程序规范,详见uni-app组件规范
接口能力(JS API)靠近微信小程序规范,但需将前缀wx替换为uni,详见uni-app接口规范
数据绑定及事件处理同Vue.js规范,同时补充了App及页面的生命周期
为兼容多端运行,建议使用flex布局进行开发

uniapp组件中父组件,子组件,兄弟组件,彼此之前的数据交换有什么?
1父传子:props
2子传父:
a子传:$emit("自定义事件名", 参数)
b父收:on+自定义事件名=“父组件的处理函数”
3兄弟组件:
aeventBus:$emit传、$on接收
b借鉴React的状态提升
cvuex
d
小程序的生命周期
应用级别:Page()中触发
onLaunch:小程序启启动时
onShow:小程序前台运行时
onHide:小程序后台运行时
onError:执行错误时
onPageNotFount:冷启动(如扫码)打开小程序的页面不存在时
页面级别:
onLoad:页面加载时触发。一个页面只会调用一次,可以在onLoad的参数中获取打开当前页面路径的参数
onShow:页面显示/切入前台时触发(返回、tabBar切换、前台运行)
onReady:页面初次渲染完毕,相当于vue的mounted。一个页面只会调用一次,代表页面已经准备妥当,可以可视图层进行交互
onHide:页面隐藏/切入后台时触发(跳转、tabBar切换、后台运行)
onUnload:页面卸载时触发。如redirectTo 或 navigateBack 到其他页面时

小程序的登陆流程
【阐述具体流程-合格】
1调用 wx.login() 获取 临时登录凭证 code
2将临时 code 传到我们的后端,后端调用换取用户唯一标识 OpenID 和 会话密钥 session_key
3后端自定义新的密钥并关联返回的 session_key 和 openid,将新的密钥返给前端,前端将其存储在 storage 中。
【登录特点-优秀】小程序登录流程主要是要与微信服务器进行通信验证
参考:
https://blog.csdn.net/allen_he_123/article/details/121111061

小程序的跳转方式
[回答第1,2,3条-合格,因为是常用的]
1wx.navigateTo() : 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
2wx.switchTab()  :  跳转到 TabBar 页面,并关闭其他所有非 tabBar 页面
3wx.navigateBack() : 关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages() 获取当前的页面栈,决定需要返回几层
[回答第4条-良好]
4wx.redirectTo() :  关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
[回答第5条-优秀]
5wx.reLaunch() :  关闭所有页面,打开到应用的某个页面
参考:https://www.jianshu.com/p/5d4c9fff5b3c

小程序的数据绑定和vue有什么区别  
参考:https://blog.csdn.net/weixin_41277748/article/details/117047654

小程序支付流程
参看:https://blog.csdn.net/weixin_46419373/article/details/108718652
场景
一般vue开发用什么库来辅助
页面刚开始出现一片空白的原因
vue的项目如何做首屏的优化

在浏览商品时,点击商品详情,然后返回,要求进度条还在之前的位置,怎么做

localstorage能实现token的存储需求,为啥还要存储在vuex中呢

项目中后台接口没有写好你怎么做,有几种方式

cookie为什么不能存储token或存储在cookie有什么问题

如果任务分配不合理你会怎么办

axios挂到原型上有什么作用

怎么知道自己项目所处的环境是什么
1环境变量:在不同的环境中,可能会设置不同的环境变量。您可以查看项目的启动脚本或配置文件,查看是否设置了环境变量,并确定当前环境下的变量值。
2配置文件:在不同的环境中,可能会使用不同的配置文件。您可以查看项目的配置文件,确定当前环境下使用的是哪个配置文件,并查看其中的配置信息。
3日志信息:在不同的环境中,可能会输出不同的日志信息。您可以查看项目的日志文件或控制台输出,查看其中的环境信息。4,代码中的配置信息:在不同的环境中,可能会使用不同的配置信息。您可以查看项目的代码,查找其中的配置信息,并确定当前环境下使用的是哪些配置信息。
cli用的是那个版本和src里面都有哪些文件


你封装过组件吗,有什么,说一下怎么封装的

怎么做项目的权限控制

axios是怎么封装的

PC端的兼容问题你遇到那些

移动端的兼容问题你遇到那些

移动端如何做真机测试

H5和app的区别


在请求回来的数据保存至localstorage里面页面没有刷新,怎么获取数据
我们知道获取数据通常会通过ajax请求后台接口来获取的。如果这个请求回来的数据保存到了localstorage中,而又不在页面刷新的情况下想要获取到数据的话
【必答】我们可以通过setInterval开启一个定时器,每隔5秒钟去访问一下localstorage中的数据,这样就可以获取到数据了。

在使用vuex时怎么实现数据的持久化
我们通常是将数据保存到本地存储中,当重新刷新页面后再从本地存储中将之前的数据加载回来保存到vuex中的state中。这样就能实现vuex的数据持久化了。

全局前置守卫的应用,自己举个小例子说出来怎么使用
【此条如果有说出-优秀】路由中的前置守卫可以监听到所有的路由跳转,并且只有在前置守卫中放行后才能真正去加载路由对应的组件并渲染出来。
【此条如果有说出-合格】所以我们可以使用前置守卫来做一些全局的判断工作,例如:我们可以使用前置守卫来做全局的登录判断,如果在前置守卫中判断没有token或者token失效了则表示没有登录,否则就是有登录,放行本地请求
ECharts 图表
ECharts由百度团队开源的可商用的图表库。
它提供了常规的折线图、柱状图、饼图、K线图;
用于地理数据可视化的地图、热力图、线图;
用于销售的漏斗图,仪表盘等
我们在开发项目时,不管是后台管理系统,还是前台网站,都有ECharts的影子,比如,商城后台订单数据统计,入款统计,退款统计等,以及销售系统,每个销售员的销售业绩统计等。最常见和应用最广也是最深的是数据大屏展示,例如,交通数据大屏,公安数据大屏,双十一销售数据大屏等
至于使用,直接参考官方文档去根据具体的需求修改出对应的配置代码后,迁移到项目中然后根据需求做特定定制化即可。它的官方文档api相当丰富,根据不同业务需求做出不同的配置即可。
有一个数组,数组都是数字怎么把里面的奇数偶数分开
【先说基本原理】因为偶数可以被2整除,奇数不能被2整除,所以可以使用 %2余数得0位偶数,否则为奇数来进行判断
【常规做法】首先通过forEach遍历数组,然后使用遍历到的数字%2如果余数为0则是偶数,否则是奇数,最后分别用两个新数组存储偶数和奇数
【良好做法】通过filter方法结合 求余 来分开

数组去重
https://blog.csdn.net/Shivy_/article/details/122595663
vuex第一次刷新导致首页空白  
【回答此句-良好】我举个例子吧,在我们做后台管理系统时,通常会采用动态添加路由的方法来实现,此方法会在登陆时利用vuex将用户信息以及菜单栏需要展示的菜单路由保存,当刷新页面的时候,vuex数据会丢失,所以动态添加路由这一步也就失效了,就会出现白屏现象。
【回答此句-优秀】只需要添加路由守卫,在每次页面刷新的时候都来判断是否添加的动态路由,如果需要即再次执行一遍添加动态路由的过程即可。
后端是使用什么来实现接口的
给我们前端ajax提供的后端数据接口通常的开发语言有:
1Java语言:现在最流行的,基本上占有90%以上的接口都是用java开发的,也是我们接触最多的
2Node.js: 一些小型项目或者不是很复杂的接口可能是前端自己开发
3Python语言、PHP语言、.Net语言,语言也都可以开发接口,但
项目中运用哪些框架,项目是否上线
项目框架组合有很多,可以自行挑选:
1【这个必答-可以自行挑选你熟悉的讲】2016年以后
aVue2+ elementUI(UI组件库)、Vue2 + iView(UI组件库)开发PC端网站
bVue-element-Admin(花裤衩)开发后台管理系统
cVue2+Vant(移动端组件库)开发移动端网站
dReact + antd(蚂蚁金服UI组件库) 开发PC端网站
eReact + antd-mobile(移动端UI组件库) 开发移动端网站
2这个能体现出你的经验】2016年以前,最常见前端框架组合【
ajQuery + BootStrap 开发网站前台和网站后台管理系统
bjQuery+layui.js 、jQuery+easyui、jQuery+extjs 开发后台管理系统
c2013年开始到2016年左右使用angularjs开发
3【这个能体现出你的经验】打包工具,2016年之前使用 gulp和grunt打包项目居多,2016年以后webpack居多
webpack有了解过么?
webpack主要是我们做工程化开发的打包工具,它会让你指定一个入口,然后通过这个入口分析出此项目的所有依赖,最终将它们打包合并成一个或者多个js文件。
同时他还有很多插件和loader能帮我们提升开发效率。
vue用了这么久 你对他有什么看法 比如语法 或者其他一些东西
可以从Vue2优点和缺点方面去讲解
优点
轻量级的框架
双向数据绑定
组件化开发
单页面路由
学习成本低
虚拟dom
渐进式框架
数据和结构的分离
运行速度快
插件化
缺点
不支持IE8以下
社区可能没有Angular和React那么丰富
Vue 不缺入门教程,可是很缺乏高阶教程与文档。同样的还有书籍
因为是单页面应用,不利于seo优化
初次加载时耗时多
服务端渲染和客户端渲染分别是什么?
服务器渲染:
页面渲染的工作都是由服务端来完成的,数据也是由服务端提供的,浏览器只负责展示页面内容
容易被爬虫爬取数据,同时能被搜索引擎搜索到,能在搜索引擎中向用户展示数据

客户端渲染:
页面的渲染工作都是由浏览器来完成的,服务器只是负责提供数据。
客户端渲染能尽早的把页面展示给用户,用户体验好
不容易被爬虫爬取数据,同时也无法被搜索引擎搜索到
移动端兼容(适配)、浏览器兼容、不同的分辨率兼容
移动端兼容(适配)参考:https://zhuanlan.zhihu.com/p/36021907
浏览器兼容参考:https://juejin.cn/post/6972937716660961317
不同的分辨率兼容 参考:https://juejin.cn/post/684490388191525274
echars有没有用在移动端?
参考:
https://www.cnblogs.com/leoxuan/p/6544351.html
自己有封装过axios吗?就是封装一个request.js
请查看人资中的封装
更复杂的请看vue3项目中的封装
和其他部门的人沟通如何处理?
1和产品经理(自研公司称呼)或者需求人员(项目外包公司称呼)确认产品设计交互流程
2和UI设计师确认UI设计稿
3和后端确认接口地址,入参,返回结果,以及结果中的字段确认,如果碰到了接口问题,找对应开发人员解决
4和测试人员确认bug出现的步骤,交流bug问题所在,如果是需求问题重新确认需求

低代码
低代码(Low Code)是一种可视化的应用开发方法,用较少的代码、以较快的速度来交付应用程序,将程序员不想开发的代码做到自动化,称之为低代码。
低代码是一组数字技术工具平台,基于图形化拖拽、参数化配置等更为高效的方式,实现快速构建、数据编排、连接生态、中台服务。通过少量代码或不用代码实现数字化转型中的场景应用创新。
参考:https://baike.baidu.com/item/%E4%BD%8E%E4%BB%A3%E7%A0%81/60863339?fr=aladdin
什么样的数据能放cdn
js、css、图片、音频、视频等静态资源
cdn的作用:
一. 静态资源加速
二. 动态资源加速
三. 音频/视频加速
四. 图片加速
五. 下载加速
六. 海外加速
七. 安全加速
具体参考:https://zhidao.baidu.com/question/927324190036530939.html
有接触即时通讯吗
基于Web的前端,存在以下几种可实现即时通讯的方式:
1、短轮询 (历史方案)
开个定时器, 每隔一段时间发请求 (实时性不强)
2、Comet - ajax长轮询(历史方案)
发送一个请求, 服务器只要数据不更新, 就一直阻塞 (服务器压力过大)
SSE(利用了http协议, 流数据的传输, 并不是严格意义的双向通信, 无法复用连接)
3、WebSocket (主流):
性能和效率都高!
参考:https://blog.csdn.net/m0_57712926/article/details/120690725
websoket具体用法参考:https://blog.csdn.net/lingshengxueyuan/article/details/107382030?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-107382030-blog-123863493.pc_relevant_aa_2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-107382030-blog-123863493.pc_relevant_aa_2&utm_relevant_index=1
怎么学习前端的
1看书
2看技术论坛
url从输入地址到访问的过程
参考:https://blog.csdn.net/ky1in93/article/details/122380722
商城购物车是怎么做的 ?在购物车订单页面怎么去更新数据?
1用户已登录:
a每次用户添加商品,向后台发送用户添加的商品。
b切换到购物车页面,从后台查询用户的购物车商品列表
c更新界面。
2用户未登录
a每次用户添加商品,在本地缓存中,存储添加的商品信息。
b每次切换到购物车页面,从本地缓存中,查询用户的购物车商品列表。
c更新页面。
后台管理的权限如何实现
现在权限相关管理系统用的框架都是element提供的vue-element-admin模板框架比较常见。
权限控制常见分为三大块
菜单权限控制
按钮权限控制
请求url权限控制。
项目优化打包
一、减少请求数量二、减小资源大小三、优化网络连接四、优化资源加载五、减少重绘回流六、性能更好的API七、webpack优化具体参考:[https://blog.csdn.net/weixin_44485276/article/details/119975366]

从上家公司出来有什么感悟
1技能方面提升:
a如:JS、项目、沟通等方面的提升。
2心态方面:
a如:学习能力、抗压能力方面的提升
本地开发怎么测试,怎么到线上去测
1 本地开发:连接开发环境的数据库,正常测试即可。
2 线上测试:
a JS报错问题:💥注意:线上发布的版本通常是压缩、混淆后的代码,控制台往往不易测试。
可以考虑通过proxy将请求转发到生产环境的服务器
在本地复现线上报错问题调试。
b 资源加载不到问题:
登录线上服务器,确认静态资源路径、是否存在等。
有没有做过一些小游戏
答:直接答没做过即可,表示可以学习。
之前前端有多少人
自己想一个数字就好,通常按照, 前端:后端 = 1:2的比例去回答
上个公司经常加班吗?
有时加有时不加,项目比较赶的时候会经常加班。
不断的加载数据,不断的生成控件,怎么优化性能
解决方案:使用虚拟列表、
工作中:使用组件库的无限滚动组件
参考:
1. 什么是虚拟列表?如何用vue实现虚拟列表
项目优化,加载速度优化
一、减少请求数量二、减小资源大小三、优化网络连接四、优化资源加载五、减少重绘回流六、性能更好的API七、webpack优化具体参考:[https://blog.csdn.net/weixin_44485276/article/details/119975366](

本地开发怎么测试,怎么到线上去测
1 本地开发:连接开发环境的数据库,正常测试即可。
2 线上测试:
a JS报错问题:💥注意:线上发布的版本通常是压缩、混淆后的代码,控制台往往不易测试。
可以考虑通过proxy将请求转发到生产环境的服务器
在本地复现线上报错问题调试。
b 资源加载不到问题:
登录线上服务器,确认静态资源路径、是否存在等。

扫码进来,有一条链接,但是我要获取链接里面带的参数,怎么获取?
1 通过URLSearchParams()

2 得到url字符串
a通过字符串的substring(1)方法,截取查询字符串
b通过字符串的split("&"),获取参数数组
c遍历参数数组,组装成参数对象
d通过对象.xxx属性名,获取参数
自己封装过方法
可以回答人资中封装的axios:
1请求拦截器
2响应拦截器
3统一异常处理


移动端兼容(适配)、浏览器兼容、不同的分辨率兼容
移动端兼容(适配)参考:https://zhuanlan.zhihu.com/p/36021907
浏览器兼容参考:https://juejin.cn/post/6972937716660961317
不同的分辨率兼容 参考:https://juejin.cn/post/684490388191525274

之前的开发流程
我们公司开发流程没有那么规范,由于系统基本上是一些常规的功能开发,所以我们也没有多少的系统分析和设计
【必答】组长和后端进行接口定好以后,我们内部有一个接口文档,已经定制好了接口地址,参数,响应回来的数据格式,然后组长搭建好基本框架和封装好通用功能后(例如,统一的ajax请求文件,路由设定等功能),我们在搭建好的框架上进行自己模块功能的开发。开发完功能就会提测,然后就是修复测试人员提交过来的bug。就这样一个个功能开发,直到完成。

websockt的使用
我们都知道前端主要是通过ajax请求一个后台提供的url地址来交互数据,而后台提供的通常是http或者https协议的url,Http或者Https协议是每次请求结束后会断开的,那么这就导致了如果服务器想给客户端主动推送数据变得不可能。所以websocket的出现就是为了解决这个问题**的。

【这个一定要说】websocket的使用是要有后端支持的,也就是java或者nodejs工程师开发一个配套websocket的接口,前端通过websocket去链接这个接口后就可以实现前后端数据交互了。

有一个数组,数组都是数字怎么把里面的奇数偶数分开
【先说基本原理】因为偶数可以被2整除,奇数不能被2整除,所以可以使用 %2余数得0位偶数,否则为奇数来进行判断
【常规做法】首先通过forEach遍历数组,然后使用遍历到的数字%2如果余数为0则是偶数,否则是奇数,最后分别用两个新数组存储偶数和奇数
【良好做法】通过filter方法结合 求余 来分开

js中怎么判断类型
判断JS类型,有以下几种方法:
[回答第1,2条-合格,因为是常用的]
1typeof :可以判断基本类型,如:number,string,boolen、symbol、undefined、null等
2. instance of:只能用来判断复杂数据类型,如:数组,方法,对象等
[回答第3条-优秀]
3object.property.toString.call:这个方法兼容基本类型和复杂类型,兼容性最好,很多框架内部都使用它来进行类型判断
参考地址:https://blog.csdn.net/weixin_43758377/article/details/117333465

切图用什么软件
现在都是使用蓝湖在线查看,或者Skech在前查看,早年使用Photo Shop软件来切图

自己封装过方法
可以回答人资中封装的axios:
1请求拦截器
2响应拦截器
3统一异常处理

有没有用过视频组件
可以回答,业务中没接触过此业务,但看过vue生态中有对应的组件库,如果需要可以很快学会。视频播放是前端的一个细分领域,有兴趣的了解下名称,开阔视野即可:
1vue-core-video-player

有没有用过websocket
1什么是websocket?
a本质: 一种双向通信协议,
b作用:常用来做即时通讯。
c场景:聊天会话、股票交易等。
2Web的前端,实现即时通讯的方式:
awebSocket (主流):性能和效率都高!参考:https://blog.csdn.net/m0_57712926/article/details/120690725websoket具体用法参考:https://blog.csdn.net/lingshengxueyuan/article/details/107382030?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-107382030-blog-123863493.pc_relevant_aa_2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-107382030-blog-123863493.pc_relevant_aa_2&utm_relevant_index=1
b短轮询 (历史方案)开个定时器, 每隔一段时间发请求 (实时性不强)
cComet - ajax长轮询(历史方案)发送一个请求, 服务器只要数据不更新, 就一直阻塞 (服务器压力过大)SSE(利用了http协议, 流数据的传输, 并不是严格意义的双向通信, 无法复用连接)

原理
事件线程的理解
线程是进程内的一个独立执行单元,是程序执行的一个完整流程,是CPU的最小的调度单元,应用程序必须运行在某个进程的某个线程上;
一个进程中至少有一个运行的线程:主线程,进程启动后自动创建
一个进程中也可以同时运行多个线程,我们说程序是多线程运行的
 一个进程内的数据可以供其中的多个线程直接共享
参考:https://blog.csdn.net/m0_59897687/article/details/123130937

JS的运行机制
答题技巧:从单线程->任务队列->EventLoop(事件循环) 宏任务和微任务依次讲解,其中如果能把EventLoop讲清楚那么是非常优秀的,如果实在不行,可以只讲 单线程->任务队列,提一下EventLoop
参考:https://zhuanlan.zhihu.com/p/88510041
图片懒加载底层原理
首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在 data-original 属性中,当页面滚动的时候需要去监听 scroll 事件,在 scroll 事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内则将图片的 src 属性设置为 data-original 的值,这样就可以实现延迟加载。
参考:https://blog.csdn.net/weixin_49733248/article/details/119305813

说一下vue2底层原理 ?vue2的特点 ?
vue 作为一种MVVM模式的框架, 其数据绑定的底层原理为:数据劫持 + 发布订阅者模式。
其中主要有这么四种“角色”:
Observer :主要负责 数据劫持, 核心是通过Obeject.defineProperty()来监听数据的变动,这个函数内部可以定义setter和getter。每当数据发生变化,就会触发setter()。这时候 Observer 就要通知给Dep 说有数据发生了变化。

Dep数据收集: Dep 收到来自 Observer 的数据变化通知时,会调用 notice() 方法把发生变化的依赖告诉 Watcher。

Watcer订阅者:是连接 Observer 和 Compile 之间通信的桥梁,当它收到来自 Dep 的数据变化通知后,会调用自身的 update() 方法,并触发Compile中绑定的回调。

Compiler 模板编译器:主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦接收到数据有变动,收到通知,更新视图。

项目逐字稿
人资分析
基于vue-element-admin搭建项目环境;使用 Element-ui 里的 form 组件实现表单校验;利用 axios 拦截器,统一设置基路径和请求头 token 及优化代码;使用 vue-router 进行页面跳转,展示对应的视图内容,并使用路由的前置守卫进行登录拦截的控制;利用 vuex 来管理共享的用户信息数据,并利用 js-cookie 将仓库数据持久化到本地存储中;使用 NProgress 插件实现页面跳转时出现在浏览器顶部的进度条;使用el-table实现表格的渲染,并使用作用域插槽对复杂数据进行回显;使用el-pagination实现分页效果,并使用size-change和current-change事件来处理当前的表格总条数和页码变化;注册全局过滤器,处理文本数据和时间的格式化;注册全局的处理图片加载失败的自定义指令;使用xlsx插件,完成excel的导入导出;使用qrcode插件,完成二维码的展示;使用vue-print-nb插件完成页面的表格的打印;使用vue-i18n插件,完成页面的中英文配置和切换;利用递归算法封装一个专门将列表型的数据,转换成树形结构的方法,并结合 Tree 树形控件行组织架构 的模块渲染;基于 RBAC 权限设计思想,控制登录用户的菜单权限和按钮权限;使用路由懒加载优化打包问题以及后期维护与更新;开发环境用 webpack 配置反向代理。【生产环境在 node 服务器配置代理 解决跨域问题】可以采用CDN的方式,在页面模板中预先引入,将项目依赖包挂载到cdn,达到优化前端包总体的体积的效果使用环境变量配置前端的不同环境下的基地址;


人资项目口语化:
本人参与的一个项目是人力资源管理后台系统,该系统所拥有的功能包括权限管理、员工管理、部门管理、权限管理等,可以通过该系统进行更好的员工信息管理以及维护,本人负责的模块包括权限路由的分配,部门管理,权限管理,员工管理。静态结构主要用了 Element-ui  组件进行编写,通过 Vue-router 进行页面之间的相互跳转,在各个管理的页面引入相对应的接口函数,请求并保存数据,然后进行渲染。

人资功能逐字稿
一、登录

我们做的人资系统是个后台管理系统, 不是人人都能访问, 于是需要登录系统.

整个登录流程大概分为三个部分

首先是使用 ElementUI 组件进行登录表单的布局

接着在这个表单当中, 用组件自带的校验功能配置好用户输入的格式校验, 包括手机号格式, 密码长度

一旦用户输入完毕, 点击登录, 其实就开始发送请求, 这里咱们将登录逻辑封装在了 vuex 里面, 不是直接调用接口, 反而是调用 vuex 的actions, 拿到token 存在 vuex 的 state 里面, 然后进行页面跳转即可

一些细节是, 刷新数据会丢失, 所以咱们用了本地储存进行数据持久化

二、角色管理页-公司设置

我们的后台管理系统中有个公司设置页面里面显示公司信息和角色管理表格

其中公司信息比较简单, 只是进入页面发送请求, 绑定到 表单中就可以, 不用做任何修改

但是角色管理就复杂一些, 是后台系统中常见的增删查改业务,首先是进入页面获取数据并且用 element ui 的表格和分页组件实现渲染的功能

新增用的是 elment ui 的 dialog 弹窗, 每当点击新增按钮的时候弹出, 里面有个表单, 带有数据的绑定和表单验证, 当用户输入完毕所有数据, 点击确定的时候, 发送请求即可, 当然为了用户的体验, 在请求前后, 做了表单校验, 用户提醒, 页面的数据更新等等优化, 如果用户点击了取消, 咱们会清理表单数据和校验再关闭, 并且这个操作不知取消按钮需要, 表单 close 事件也需要, 为的是照顾点击右上方 X 按钮操作.

编辑时其实是复用了新增弹窗, 区别在于, 会在点击时带上被点击角色 id, 向后端获取详情回填到表单上再弹起弹窗,还有就是会在用户点击确定时, 根据表单有没有 id 存在决定是新增还是编辑请求.

删除时最简单的功能, 点击时带上id, 发送请求即可, 当然为了用户体验, 删除前后, 加上了二次询问, 提示用户和更新页面的操作.

三、组织架构(部门页)

我们在人力资源管理系统当中, 有一个部门管理页面, 主要是用来添加删除编辑部门的数据这个页面比较复杂进入页面时是普通的数据查询获取到后台部门列表, 进行渲染即可这里有两个问题, 第一是树形组件需要递归数据, 第二树形渲染需要自定义样式, 我们封装了一个函数, 对后台传出来的数据进行了转换, 把原本通过 pid 进行上下级关联的数据转成 elment ui 要求的 children 嵌套, 另外使用作用域插槽自定义了树形组件渲染, 这个逻辑比较复杂, 我们封装在了一个树形组件 tree-tools 当中

查询完成之后, 咱们做了新增和编辑删除的功能, 因为新增和编辑功能比较复杂, 也是封装了一个组件作为弹窗, 里面有一个表单, 供用户输入部门数据, 点击确定后就能发送请求进行数据处理

这个页面最难的点在于, 树形子组件+父页面+弹窗子组件之间的交互, 因为点击树形子组件时需要将弹窗弹起来, 并且弹窗也需要知道到底是哪个部门触发了新增和编辑, 解决方案是, 通过父页面作为桥梁, 间接实现树形和弹窗通讯, 逻辑是,每当树形被点击, 将事件和被点击的id往父页面传, 父页面存储到 data 以后再传给 弹窗组件即可

这里面还做了一个附加的校验功能, 部门名称在同一个父部门下不能重名, 部门编码, 在整个公司都不能重复, 这里使用到了element ui 表单中的自定义校验函数, 每当输入框失去焦点就会触发校验函数, 在里面我们拿到整个公司的部门列表, 根据需要跟用户, 如果有重复就报错, 最终实现发送请求之前完成重名校验

删除时最简单的, 就是带上 id 发个请求即可, 后续有提醒用户, 更新页面数据等体验上的操作

四、员工管理

员工管理页面,主要是实现员工的增删改查,批量导入导出员工功能。

首页进入页面是需要接口获取到员工列表数据,然后配置elementUI组件进行渲染。

新增员工主要用到dialog组件和表单组件配置新增接口实现新增功能。

编辑员工,主要是员工详情信息比较多,所以是配置了一个独立的路由页面来实现功能的,首先是获取到员工id,然后根据员工id进行数据回显,然后再调用编辑接口实现员工信息的修改,这里涉及到腾讯云cos(对象存储)的使用,因为所有的员工头像都是上传到腾讯会cos中的,腾讯云cos使用的注意点就是需要添加允许跨域的配置,其他只需要按照文档实现即可,这里我们也专门封装了一个功能上传图片的组件出来。

删除员工,只需要点击删除按钮的时候获取到该员工的id,然后调用删除接口实现删除功能,这里我们也考虑到了误删的情况,因此点击删除按钮的时候会先显示“是否确认删除”的询问框,当用户再次确认的时候才实现真正的删除。

批量导入导出功能,这个功能主要是利用xlsx插件实现导入导出功能,这里的难点是导出的时候,需要把请求到的数据转换为xlsx要求的格式才能导出成功;实现批量导入功能的时候,也需要把通过xlsx插件解析好的Excel表格数据转换为接口需要的数据格式。

比如:批量导入数据时,因为获取到的Excel表格数据字段都是中文名的,但是后端接口需要的是英文名,因此我们把数据通过接口传递给后端之前需要先把数据转换为后端规定的格式,我们的做法是先准备好一个中英文字段对照字典表,然后再根据字典表把Excel表格的中文字段名替换成英文字段名,从而实现数据转换。(注意:这一段如果面试官 没有问题具体数据是怎么转换的,不需要跟面试官讲,如果问到了可以这样回答)

五、权限设置

人资项目中有一个权限设置页面,这个页面主要是用来实现权限数据的增删改查。

首先进入页面通过接口获取到全选数据,然后配置elementUI的表格组件进行渲染。因为权限分为页面访问权限和按钮操作权限因此渲染的时候需需要把数据渲染成一个表格的树形结构,因此我们获取到数据后首先通过一个递归函数把数据转为树形结构,然后再配合表格组件的用法渲染成一个表格树形结构的。

然后是新增权限功能,新增权限功能要注意的是需要区分新增的是按钮操作权限还是页面访问权限,如果是页面访问权限的话必须要传递固定的2个参数给后端,pid为0,type为1,以此表示此刻用户添加的是页面访问权限,当添加的是按钮操作权限的时候,传递pid为页面访问权限的id,type为固定值2,以此表示用户此刻添加的是按钮操作权限。

编辑权限功能直接复用新增功能的结构样式,编辑权限的时候首先要获取到点击的那个权限的id并通过该id获取权限详情数据最后进行数据回显,然后调用编辑权限接口,传入新的数据从而实现编辑功能。

删除功能相对比较简单,只需要点击删除按钮的时候获取到该权限的id,然后调用删除接口实现删除功能,这里我们也考虑到了误删的情况,因此点击删除按钮的时候会先显示“是否确认删除”的询问框,当用户再次确认的时候才实现真正的删除。

六、RBAC权限设计

人资项目权限设计用到的是现在比较流行的一种设计模,叫RBAC的权限设计模式,这个模式主要有3个部分构成,员工,角色以及权限,我们要做的就是先完成员工,角色,以及权限的增删改查,然后给员工添加角色,给角色添加权限,这样员工就具有对应的权限了,我们这里的权限主要是两个方面的权限,一个页面访问权限,一个是按钮操作权限。

当我们在系统中完成了权限配置之后,员工登录系统可以通过一个接口获取到该员工的“页面访问权限点”和“按钮操作权限点”。那么我们可以根据获取到的这些权限点来分别动态设置页面的访问权限和按钮操作权限。

页面访问权限,先通过获取到的“页面访问权限点”筛选出来具有权限的路由对象,然后是通过路由的一个addRoutes方法实现动态路由权限的添加,。

按钮操作权限主要是通过mixin混入一个全局函数,在函数中通过“按钮操作权限点”查找某个按钮是否具有操作权限,有权限则返回true,否则返回false,最后配置v-if指令实现按钮显示隐藏,从而实现设置按钮操作权限。

七、主页

主页部分主要实现展示日历,流程申请,公告,等信息。

其中日历我们是利用elementUI的组件进行了二次封装,并且对日历的内容进行自定义的显示,比如周末可以在日历中显示一个“休”字(自定义内容主要是因为日历组件提供了作用域插槽给我们使用,才能够实现自定义内容的功能)。

流程申请主要是可以进行“加班离职”,“请假调休”等等的申请,我们直接使用elementUI的dialog组件配合表单组件来实现申请的布局,然后通过调用相应的接口实现申请功能。

公告主要是通过接口获取公司发布的一些公告信息进行展示。

项目优化&代码编写过程

增加员工、修改员工信息弹窗还有图片上传的组件封装, ESlint  的代码格式化,编写代码时更加严谨,运用 Git 管理 多人共同开发
黑马u购逐字稿
https://www.yuque.com/docs/share/674f21ae-e6bd-487d-9711-b53043c7b77a?# 《黑马优购 - 微信小程序商城项目逐字稿》  

小兔鲜儿逐字稿
项目搭建
我们做的小兔鲜儿项目是个电商网站,使用到了 Vue3 技术。
项目都是我们从0到1搭建的,都是按 Vue3 的最新标准操作。
脚手架用的是 Vite,技术栈是 Vue3 + TS + Pinia,使用组合式API的 setup 语法糖开发。
脚手架 Vite 配置了:路径别名,服务器代理,setup语法糖拓展插件,less 变量自动导入等。
风格管理我还配置了 ESlint + Prettier + EditorConfig 做统一格式化,按保存就能自动根据配置格式化,防
止提交的时候,为了方便其他同事开发的时候保持一样风格,我还做了一些工作区配置和插件推荐集成
到项目中 setting.json 和 extensions.json。
axios 请求库针对 TS 类型进行了封装一层,让接口的返回值有更好的TS类型提示,项目中的接口类型声
明文件也做了统一的规划管理。
首页模块
首页和很多页面的头尾都是一样的,做了一些路由的划分,封装了公共的头部和尾部组件。
由于封装抽离了,就要考虑到状态管理的问题,整个首页的数据都通过Pinia做全局状态管理。
首页的为了增强用户体验,也增加了一些交互特效如导航滚动吸顶,返回顶部等,首页楼层的一些重复
的部分都抽离成组件方便复用。
因为PC端没有合适的组件库,首页的轮播图组件,骨架加载组件都是自己封装的,其实整个项目的组件
库都是自己用 Vue3 + TS 封装的,使用时还支持类型提示和校验。
这里封装组件库的时候遇到了一个难点,就是把自己封装的组件库作为全局组件之后,就没有了TS的类
型检查和提示了,这里我是借鉴了 Element-Plus 的源码最后找到了解决方案,自己为组件库写了个类型
文件之后,项目中全局组件也能有类型提示了。
首页还做了一个懒加载的优化和数据缓存优化。懒加载的思路是模块进入可视区后,再发送请求获取数
据,最终渲染组件。数据缓存通过Pinia的插件实现打开首页速度更快。
懒加载的功能比较常用,所以我用组合式API直接封装成了一个 hooks 钩子函数方便复用。
分类模块
分类模块整体比较简单一些,主要是分类和商品的列表渲染。
但是在处理的过程中也遇到了两个路由的问题。第一个是路由的缓存,点击顶部切换分类的时候,不会根据新的分类id请求新的分类数据,解决方案是
给二级路由的 RouterView 加 Key 值为路由的 fullPath 就能解决,其实还有一个解决方案,可以通过
watch 侦听路由的 fullPath ,如果变化就重新发送请求渲染新的分类数据。
第二个问题是滚动行为,切换分类的时候需要返回顶部,处理起来比较简单,踩坑的原因是主要是新版
VueRouter 的API变了,查最新官方文档后解决了,后来再系统看了一遍官方文档就没踩什么新的坑了。
详情模块
详情模块以内容展示为主。
难点是在这个页面需要自己封装一些组件,如商品切换效果组件,地址选择组件,商品数量组件,加载
中,消息提示组件,按钮组件,商品规格选择组件。
其中按钮组件虽然简单,为了更好的TS类型提示,也遇到了TS类型 props 默认值的问题,最后查阅最新
官方文档其实有三种解决方案,最简单的是基于 JS 的基础上添加类型断言,还可以通过 withDefaults 和
最新的响应性语法糖解决。
商品数量组件需要通过 v-model 实现双向绑定,Vue2 和 Vue3 组件的 v-model 有些差异,Vue2 的 :value
改名为了 modelValue,@input 事件改名为了 @update:modelValue,这些都可以在 Vue3 的官方文档查
阅。Vue3 现在最新的官方文档真的好用,不过中文版还没正式发布,我都是通过查 GitHub 开源仓库的
时候找到的这个未发布的中文官网并分享给了同事。
登录模块
项目支持多种登录方式:有账号密码登录,手机号+验证码登录和第三方授权登录。
登录逻辑我都是封装到了 Pinia 中,添加一种新的登录方式只需要添加一个新的 actions 就可以了,并且
方便进行全局状态管理,登录成功后返回的 token 也是通过 Pinia 自动同步到本地防止页面刷新后数据
丢失。
第三方QQ授权登录,前端需要 appid 和登录成功后的回调地址。
回调地址需要配置环境才可以实现,如登录回调地址需要修改电脑的 hosts 文件和项目 vite 脚手架的配
置。
在QQ登录成功后,可以通过QQ互联的API获取QQ用户信息,OpenId 做登录绑定,如果已经绑定账号过
的用户都是可以一键授权登录的。
这里有个小插曲,QQ互联的API源码是用JS写的,我项目是TS开发并且还配置了Eslint,直接引入 JS 代
码会报类型错误和全局变量错误,这里我是通过手写 TS 类型声明文件 + eslint 配置全局变量解决的。
购物车模块
我们的项目是分为两种状态的购物车。一种是用户已登录,还有一种就是用户未登录,这里也拆出来一
个 Pinia 模块管理购物车。
已登录版的购物车相对比较简单,只需封装一个个的 actions ,如加入购物车,删除商品,修改数量和
选中状态,在用户操作的时候调用对应接口就可以了。未登录的版本就麻烦一些,加入购物车,删除商品,修改数量和选中状态这些逻辑都由前端完成,为了
防止刷新数据丢失,还需要自动同步到本地存储。
购物车如何区分已登录和未登录两种状态,我是先把用户登录信息缓存到购物车模块的 getters 中,在
每一个 actions 内部进行登录状态判断,用户已登录那就调接口,未登录前端完成增删改查逻辑,这样
就能实现在组件中调用 actions 的时候更方便,也方便后期维护,用户登录和退出与购物车的逻辑也是
做了同步处理的,登录合并购物车,退出清空购物车。
这里还有个小细节就是,未登录状态如何保持本地商品的信息是最新的,这里我封装了一个 action ,在
本地版购物车进行增删改查的时候,主动调用接口查询最新商品信息库存和价格。当然在用户首次进入
网站的时候,也会同步购物车列表所有商品的库存和价格。
订单与支付模块
下单要求用户登录,不是人人都能访问,这里我通过设计路由导航守卫进行判断,如果用户未登录就跳
转到登录页,并且完成了登录成功后的页面回跳到原来的页面,提升用户体验。
下单需要用户选择收货地址,收货地址的弹出的对话框也是自己封装到组件库中,这里还用到了 Vue3
新增的 Teleport 传送门组件防止出现对话框定位的 Bug 。
用户提交订单后就会生成一个订单号,并且跳转到支付页面,下单页面的倒计时我也封装了一个 hooks
函数,方便在项目中复用。
下单后可以用支付宝完成支付,支付成功后就会回跳到支付结果页,用户也可以在个人中心查询到支付
或未支付的订单。微信支付由于还没接口所以没有实现,不过流程也都差不多。
会员中心

相关文章
|
存储 SQL 分布式计算
浅谈MPP数据库-Vertica
用过这块数据库3年时间,很多功能非常强大,POC做了很多数据库,查询性能可以说是最好的,推荐一下
3481 2
|
6月前
|
缓存 前端开发 JavaScript
头条面经
涵盖前端、网络、JS核心、框架及算法等多方面知识,包括深拷贝、双向绑定、HTTP缓存、跨域、Vue原理、TCP/UDP、设计模式、事件循环、类型判断、闭包、原型链、性能优化等高频面试题,全面考察技术深度与综合能力。
|
8月前
|
消息中间件 存储 缓存
如何设计10亿用户级的微博Feed流系统并应对100W QPS的挑战?
本文详解微博Feed流系统设计,涵盖Timeline与Rank模式、推拉结合机制及四层雪崩防护体系,分享应对百万QPS高并发的架构经验,助力构建高效、稳定的大规模社交系统。
|
7月前
|
关系型数据库 MySQL BI
为什么实时更新场景下 Doris 查询性能是 ClickHouse 的 34 倍
企业数据分析能力从TP系统起步,随业务发展历经扩展优化,最终走向AP系统独立建设。Apache Doris凭借高并发、低延迟、实时更新与强查询性能,成为实时分析架构升级的理想选择,助力网易云音乐、快手、拉卡拉等企业实现性能倍增与成本优化。
562 12
为什么实时更新场景下 Doris 查询性能是 ClickHouse 的 34 倍
|
Prometheus Kubernetes 监控
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
|
11月前
|
JSON 安全 Go
Go语言项目工程化 —— 日志、配置、错误处理规范
本章详解Go语言项目工程化核心规范,涵盖日志、配置与错误处理三大关键领域。在日志方面,强调其在问题排查、性能优化和安全审计中的作用,推荐使用高性能结构化日志库zap,并介绍日志级别与结构化输出的最佳实践。配置管理部分讨论了配置分离的必要性,对比多种配置格式如JSON、YAML及环境变量,并提供viper库实现多环境配置的示例。错误处理部分阐述Go语言显式返回error的设计哲学,讲解标准处理方式、自定义错误类型、错误封装与堆栈追踪技巧,并提出按调用层级进行错误处理的建议。最后,总结各模块的工程化最佳实践,助力构建可维护、可观测且健壮的Go应用。
|
网络协议 API PHP
探索PHP的异步编程:使用ReactPHP实现非阻塞I/O
【8月更文挑战第4天】在传统的同步编程模型中,PHP脚本按顺序执行,每个任务必须等待前一个任务完成后才能开始。这种模式在处理I/O密集型操作时,如网络请求或文件读写,会导致性能瓶颈。异步编程提供了一种解决方案,允许多个操作同时进行,从而提高效率。本文将介绍如何使用ReactPHP库在PHP中实现异步编程,并通过代码示例展示其如何优化I/O操作。
691 1
|
Java UED 开发者
Spring Boot 降级功能的神秘面纱:Hystrix 与 Resilience4j 究竟藏着怎样的秘密?
【8月更文挑战第29天】在分布式系统中,服务稳定性至关重要。为应对故障,Spring Boot 提供了 Hystrix 和 Resilience4j 两种降级工具。Hystrix 作为 Netflix 的容错框架,通过隔离依赖、控制并发及降级机制增强系统稳定性;Resilience4j 则是一个轻量级库,提供丰富的降级策略。两者均可有效提升系统可靠性,具体选择取决于需求与场景。在面对服务故障时,合理运用这些工具能确保系统基本功能正常运作,优化用户体验。以上简介包括了两个工具的简单示例代码,帮助开发者更好地理解和应用。
606 0