Vue面试

1.Vue响应式原理

整体思路是:数据劫持+观察者模式

通过Object.defineProperty方法和Proxy对象来劫持各个属性的setter、getter,内部Vue追踪依赖,当数据发生变动时发布消息给订阅者,触发相应的监听回调。

Vue2的响应式原理:

Vue2通过Object.defineProperty对data中的属性进行劫持,当属性值发生变化时,会触发对应的更新函数,从而更新视图。

Vue2通过Watcher来实现数据与视图的双向绑定,当数据发生变化时,Watcher会通知对应的视图进行更新。

Vue2的响应式原理存在一些缺陷,例如无法监听数组的变化,需要通过特殊的方法来实现.

Vue3的响应式原理:

Vue3使用Proxy代替了Object.defineProperty,Proxy可以监听到对象的所有属性,包括新增和删除操作。

Vue3使用了WeakMap来存储依赖关系,避免了Vue2中Watcher的内存泄漏问题。

Vue3支持了多个根节点的组件,可以更方便地进行组件的复用和组合。

 原生JS如何实现数据的双向绑定:

步骤 1: 创建HTML结构

首先需要一个HTML元素来展示数据并且允许用户编辑数据。

<input id="a1" oninput="handleChange()" />
<span id="a2"></span>

步骤 2: 编写JavaScript代码

接下来编写JavaScript代码来实现数据和输入框之间的双向绑定

let input = document.getElementById('a1');let span = document.getElementById('a2');let data = {};Object.defineProperty(data, 'val', {get: function () {return val; },set: function (newVal) {val = newVal; input.value = val; // 更新 input 的值span.innerHTML = val; // 更新 span 的值}});function handleChange() {data.val = input.value; // 当输入框值改变时,更新 data.val}

2.$route 和 $router的区别

在 Vue.js 框架中,特别是当使用 Vue Router 进行单页应用的路由管理时,$route$router 是两个非常重要的概念。它们都是由 Vue Router 提供的,并且可以在 Vue 组件实例中直接访问。

$router

$router 是一个 Vue Router 实例对象,它包含了操作路由的方法和属性。通过 $router,你可以执行导航、获取所有路由等操作。例如,你可以使用 $router.push() 方法来导航到一个新的路由。

常用方法:

  • push(location): 导航到一个新地址。
  • replace(location): 导航到一个新地址,但不会向 history 添加新记录。
  • go(n): 在 history 中前进或后退 n 步。
  • back(): 返回上一步。
  • forward(): 前进一步。
  • getCurrentRoute(): 获取当前的 route 对象(在 Vue 3 中为 currentRoute)。

$route

$route 是一个只读对象,它代表了当前激活的路由的状态。它包含了一系列与当前 URL 相关的信息,如路径、查询参数等。

常用属性:

  • name: 路由的名称。
  • path: 完整的路径字符串。
  • params: 匹配动态片段和全匹配模式的参数对象。
  • query: 查询参数对象。
  • hash: 哈希部分。
  • meta: 附加元信息的对象。

总结来说,$router 主要用于控制路由跳转和获取路由信息,而 $route 则是用于读取当前路由的信息。

3.为什么data属性是一个函数而不是一个对象

  1. 避免数据污染

    • 当 data 是一个对象时,如果多个 Vue 实例共享同一个构造函数,那么这些实例将会共享同一个 data 对象。这意味着改变其中一个实例的数据会影响到其他实例的数据,这显然是不希望发生的。
  2. 每次创建新实例时返回新的数据对象

    • 使用函数可以保证每次创建新的 Vue 实例时都会调用该函数,从而返回一个新的数据对象。这样可以确保每个实例都有自己独立的数据副本,避免了数据之间的相互影响。
  3. 易于理解和维护

    • 将 data 定义为函数使得代码更加清晰,有助于理解 Vue 实例是如何初始化的,并且有助于维护和调试。
  4. 性能考虑

    • 如果 data 是一个对象,那么在创建多个实例时,所有实例都将引用同一个对象,这可能会导致意外的行为。使用函数可以避免这种性能上的问题,因为每个实例都拥有自己的数据。

总之,Vue.js 设计 data 为一个函数是为了确保每个实例拥有独立的数据绑定,避免实例之间数据的冲突,并且有利于维护和理解代码

4. 说出$nextTick的作用

$nextTick 是 Vue.js 中的一个非常有用的方法,它主要用于确保某些操作在 DOM 更新之后执行。当你修改了数据模型之后,Vue 会异步更新 DOM,以提高性能。如果你需要在数据变化后立即访问更新后的 DOM,就需要使用 $nextTick

主要作用

  1. 等待 DOM 更新

    • 当你改变了组件的状态,但需要确保 DOM 已经完成更新后才能进行某些操作时,可以使用 $nextTick
  2. 确保数据变化后执行回调

    • 如果你需要在数据变化并且视图更新后执行某些操作(比如重新计算布局、触发第三方库的某些功能),可以将这些操作放在 $nextTick 的回调函数中。

总结来说,$nextTick 的主要作用是在数据变化后确保 DOM 更新完毕,这对于依赖于最新 DOM 状态的操作非常重要。

5. diff算法

diff 算法通常指的是用于比较和更新虚拟 DOM 树的算法。

Diff 算法的核心思想

Diff 算法的主要目标是确定哪些部分需要更新,从而最小化实际 DOM 的操作次数。这是因为直接操作 DOM 是昂贵的操作,而虚拟 DOM 的更新则相对便宜。

Vue.js 的 Diff 算法

Vue.js 也采用了一种高效的 diff 算法来更新 DOM。Vue 的 diff 算法同样关注于最小化 DOM 更新,但它有一些不同的策略:

  1. 异步更新队列:Vue 将数据变化收集起来,在下一个事件循环开始时一次性更新 DOM,这有助于减少不必要的重绘和重排。
  2. 局部更新:Vue 只更新发生变化的部分,而不是整个树。
  3. 利用缓存:Vue 会缓存一些信息,如节点的位置,以便更快地定位需要更新的节点。

关键步骤

无论是 React 还是 Vue.js,diff 算法通常包括以下步骤:

  1. 标识差异:比较新旧虚拟 DOM 树,找到需要更新的节点。
  2. 最小化更新:确定最少量的更新操作,如添加、删除、移动或替换节点。
  3. 应用更新:将这些更新应用到实际 DOM 上。

Diff 算法是现代前端框架中的关键技术之一,它通过比较虚拟 DOM 树的变化来最小化实际 DOM 的更新,从而提高应用程序的性能。

 6.Vue3相比Vue2的优势

Vue 3 引入了新的响应式系统,使用 Proxy API 替换了 Object.defineProperty,这使得依赖追踪更加高效且易于实现。

 Vue 3 提供了 Composition API,这是一种新的编程模型,可以帮助开发者更好地组织和复用逻辑代码。这使得组件内部的逻辑更加清晰和模块化。

Vue 3 对 TypeScript 的支持更加完善,提供了更好的类型定义,使得类型检查更加精确,同时降低了使用 TypeScript 的门槛。

7.Vue2里的性能优化

v-for 遍历避免同时使用 v-if
  1. 性能问题:每次循环都会检查 v-if 的条件,这可能导致不必要的计算,特别是在数组较大时。

  2. 渲染效率低:由于 v-if 会在每次循环时都被评估,即使某些项最终不会被渲染,也会增加渲染时间。

  3. 可维护性差:同时使用 v-ifv-for 可能会使代码难以阅读和维护,尤其是当条件变得复杂时。

为了避免这些问题,推荐的做法是提前过滤数据:使用Computed、v-show替代v-if、使用filter()

 巧用计算属性

计算属性是一种处理数据用来解决代码的冗余的方式,当处理不需要常变化的值推荐使用这个。计算属性就有缓存机制,这种机制可以提高我们的性能。

使用防抖与节流控制发送频率
路由守卫处理请求避免重复发送请求

8.扁平化数组代码实现

1. 使用 flat() 方法

ES2019 引入了 flat() 方法,这是一个非常方便的方法来扁平化数组。它可以接受一个可选的深度参数,该参数指定了应该扁平化的深度。

const nestedArray = [1, 2, [3, 4], 5, [6, [7, 8]]];// 默认只展开一层
const partiallyFlattened = nestedArray.flat();
console.log(partiallyFlattened); // 输出: [1, 2, 3, 4, 5, 6, [7, 8]]// 展开所有层级
const fullyFlattened = nestedArray.flat(Infinity);
console.log(fullyFlattened); // 输出: [1, 2, 3, 4, 5, 6, 7, 8]
2. 使用递归

如果你无法使用 flat() 方法或者需要更复杂的逻辑,可以使用递归来手动扁平化数组

function flatten(array) {return array.reduce((acc, val) => Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []);
}const nestedArray = [1, 2, [3, 4], 5, [6, [7, 8]]];
const flattened = flatten(nestedArray);
console.log(flattened); // 输出: [1, 2, 3, 4, 5, 6, 7, 8]
3. 使用 reduce() 和 concat()

你可以使用 reduce() 方法结合 concat() 方法来扁平化数组。

const nestedArray = [1, 2, [3, 4], 5, [6, [7, 8]]];const flattened = nestedArray.reduce((acc, val) => Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []);console.log(flattened); // 输出: [1, 2, 3, 4, 5, 6, 7, 8]

9.数组去重

 1.利用新旧数组遍历对比法
arr=[1,5,1,3,5,4,3,9,8]let newArr = [];/*   indexOf用于查找数组元素第一次出现的位置,没找到则返回值为-1,参数有两个,第一个为元素项目,参数二(可选)需要查找的位置,负数从-1往前面加 */
for (let i=0;i<arr.length;i++) {if (newArr.indexOf(arr[i]) === -1) {newArr.push(arr[i]);}}
console.log(newArr);//[1, 5, 3, 4, 9, 8]
2.利用新语法 new Set()
arr=[1,5,1,3,5,4,3,9,8]
let mySet = new Set(arr); // 非重复的类数组
console.log(mySet,'mySet');//{{1, 5, 3, 4, 9,8}
// let newArr = Array.from(mySet); // set转数组
let newArr = [...mySet]; // 或者是这种解构方法
console.log(newArr);//[1, 5, 3, 4, 9, 8]
3.使用includes()
arr=[1,5,1,3,5,4,3,9,8]
let newArr = [];
for (let i=0;i<arr.length;i++) {if (!newArr.includes(arr[i])) {newArr.push(arr[i]);}
}
console.log(newArr);//[1, 5, 3, 4, 9, 8]

10.事件循环机制

在前端开发中,事件循环(Event Loop)机制是 JavaScript 引擎处理异步任务的关键机制之一。事件循环负责协调同步任务与异步任务的执行顺序,确保 JavaScript 的执行是单线程的同时又能处理异步操作。

事件循环理论先执行同步任务,再去执行我们的异步任务(先执行微任务再执行宏任务)。

实例:

console.log('Start');setTimeout(() => {console.log('Timer 1');
}, 0);Promise.resolve().then(() => {console.log('Promise');
});setTimeout(() => {console.log('Timer 2');
}, 0);console.log('End');

输出结果:

Start

End

Promise

Timer 1

Timer 2

解释:

  1. 首先输出 "Start"。
  2. setTimeout 设置了两个延时 0ms 的定时器任务,它们会被放入消息队列。
  3. Promise.resolve().then() 是一个微任务,将在当前宏任务(全局执行上下文)结束后立即执行。
  4. 最后输出 "End"。
  5. 微任务执行,输出 "Promise"。
  6. 事件循环处理消息队列中的第一个宏任务,输出 "Timer 1"。
  7. 处理第二个宏任务,输出 "Timer 2"。

11.事件冒泡

事件冒泡(Event Bubbling)是一种重要的事件传播机制。当用户与网页上的某个元素进行交互时(如点击按钮),浏览器会触发相应的事件。事件冒泡描述了事件如何从触发事件的最内层元素开始,逐步向上传播到父元素,直至到达文档的根元素的过程。

事件冒泡的特点

  • 从内到外:事件首先在最内层的元素上触发,然后逐步向上传播到父元素,直到到达文档的根元素(通常是 <html> 元素)。
  • 事件捕获与事件冒泡:与事件冒泡相对应的是事件捕获(Event Capturing),这是一种相反的传播机制,事件首先从根元素开始向下传播,直到到达最内层的元素。不过,事件捕获在实际开发中较少使用。
  • 阻止事件冒泡:可以通过特定的方法来阻止事件的冒泡行为,例如使用 event.stopPropagation()

事件冒泡的用途

  • 事件委托:事件冒泡使得事件委托成为可能,这是一种优化事件处理的常用技术。通过在较高级别的元素上绑定事件处理器,而不是在每个子元素上单独绑定,可以减少事件监听器的数量,从而提高性能。
  • 简化事件处理:事件冒泡简化了事件处理逻辑,因为可以将事件处理器绑定到父元素上,而不必为每个子元素单独绑定。

示例

下面是一个简单的 HTML 示例,演示了事件冒泡的工作原理:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡示例</title>
<script>
document.addEventListener('DOMContentLoaded', function() {const div = document.getElementById('outer');const button = document.getElementById('button');// 为外部 div 绑定事件处理器div.addEventListener('click', function(event) {console.log('Div clicked');});// 为按钮绑定事件处理器button.addEventListener('click', function(event) {console.log('Button clicked');});
});
</script>
</head>
<body>
<div id="outer" style="border: 1px solid black; padding: 10px;"><button id="button">Click me!</button>
</div>
</body>
</html>

分析

在这个示例中:

  • 当点击按钮时,首先会触发按钮上的点击事件处理器,输出 "Button clicked"。
  • 然后事件会冒泡到外部的 div 元素,触发该元素上的点击事件处理器,输出 "Div clicked"。

阻止事件冒泡

如果你想阻止事件冒泡,可以使用 event.stopPropagation() 方法。下面是一个修改过的示例,展示了如何阻止事件冒泡:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>阻止事件冒泡示例</title>
<script>
document.addEventListener('DOMContentLoaded', function() {const div = document.getElementById('outer');const button = document.getElementById('button');// 为外部 div 绑定事件处理器div.addEventListener('click', function(event) {console.log('Div clicked');});// 为按钮绑定事件处理器,并阻止事件冒泡button.addEventListener('click', function(event) {console.log('Button clicked');event.stopPropagation(); // 阻止事件冒泡});
});
</script>
</head>
<body>
<div id="outer" style="border: 1px solid black; padding: 10px;"><button id="button">Click me!</button>
</div>
</body>
</html>

事件冒泡是前端开发中一个非常重要的概念,它描述了事件如何从触发事件的最内层元素开始,逐步向上传播到父元素的过程。理解事件冒泡有助于优化事件处理逻辑,并且对于实现事件委托等高级功能至关重要。

12.闭包 

闭包是由函数和与其相关的引用环境组合而成的实体。换句话说,闭包就是能够读取其他函数内部变量的函数。在 JavaScript 中,每当一个函数被创建时,它就会形成一个闭包,因为它可以访问其外部作用域中的变量。

function outerFunction() {let count = 0;function innerFunction() {count++;console.log(count);}return innerFunction;
}const incrementCounter = outerFunction();incrementCounter(); // 输出: 1
incrementCounter(); // 输出: 2
incrementCounter(); // 输出: 3

闭包的注意事项

  1. 内存泄漏

    • 闭包可能会导致内存泄漏,因为它们可以让变量一直存在于内存中,即使这些变量不再被需要。
    • 请注意清理不再需要的引用,以避免内存泄漏。
  2. 性能考量

    • 创建大量的闭包可能会消耗较多的内存,尤其是在大型应用程序中。
    • 在适当的地方使用闭包,并注意性能优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/51656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

完全二叉树的基本操作

二叉树节点类型 typedef struct node { int no; struct node *pleftchild; struct node *prightchild; }treenode; 一.创建完全二叉树 传入起始编号&#xff08;1&#xff09;和结束编号&#xff08;k&#xff09; ptmpnode malloc(sizeof(treenode)); ptmpnode->pl…

Redis基本全局命令

文章目录 get和setkeysexistsdelexpirettltype redis全局命令&#xff1a; redis支持很多种数据结构&#xff0c;整体上来说。redis是键值对结构&#xff0c;key固定就是字符串&#xff0c;value实际上就会有很多种&#xff0c;比如说&#xff1a; 字符串哈希表列表有序集合 …

TCP ISO/OSI模型

OSI参考模型在网络层支持无连接和面向连接的通信&#xff0c;但在传输层仅有面向连接的通信。而TCP/TP模型认为可靠性是端到端的问题&#xff0c;因此它在网络层仅有一种无连接的通信模式&#xff0c;但在传输层支持无连接和面向连接两种模式。 针对上述问题我想再做一点…

C++|初始化自定义结构体的几种方式

在C中&#xff0c;初始化自定义结构体有多种方式&#xff0c;每种方式都有其适用场景。以下是一些常见的初始化方法&#xff1a; 直接初始化&#xff1a; struct MyStruct {int x;double y; };MyStruct s1 {10, 3.14};列表初始化&#xff08;C11及以后版本&#xff09;&#x…

住宅物业满意度计算方式中满意率和满意度指数的区别

满意率和满意度指数是用于计算住宅物业满意度的两种不同方式&#xff0c;它们的区别如下&#xff1a; 1、满意率&#xff1a;满意率是通过计算满意的居民人数与总参与调查的居民人数之间的比例来衡量满意度。它以百分比形式表示&#xff0c;可以直观地了解居民对物业管理的整体…

集运系统如何多维度展现企业业务情况?

在集运行业&#xff0c;数据是企业决策的重要依据。为了在竞争中保持优势&#xff0c;企业需要一套高效、灵活且可靠的管理工具来应对市场的快速变化。易境通集运系统以其全面而精细的统计报表功能&#xff0c;成为企业决策优化和业务增长的重要助手。 易境通集运系统https://…

使用在AMD GPU上运行的ROCm进行大语言模型的自然语言处理任务

Performing natural language processing tasks with LLMs on ROCm running on AMD GPUs — ROCm Blogs 在这篇博客中&#xff0c;您将学习如何使用在AMD的Instinct GPU上运行的ROCm进行一系列流行且有用的自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;使用不同的大…

新手该如何选择与小程序定位相关的关键词

关键词的优化是提高小程序排名的关键步骤之一&#xff0c;所以如何选择与小程序定位相关的关键词是一个很重要的过程&#xff0c;需要考虑多个因素以确保关键词既符合小程序的业务特性&#xff0c;又能吸引目标用户。以下是一些具体的步骤和建议&#xff1a; 1. 深入了解小程序…

Go发布自定义包

1、初始化go.mod go mod init github.com/xumeng03/images2、编写包内容 这里只是一个简单的压缩jpg/jpeg图片例子&#xff0c;代码参考 https://github.com/disintegration/imaging 2.1、fs.go package imagesimport ("image""io""os""p…

Vue3中的defineExpose的认识

文章目录 defineExpose子组件父组件&#xff1a;总结&#xff1a; defineExpose 使用 <script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例&#xff0c;** 不会 **暴露任何在 <script setup> 中声明的绑定。 可以通过 def…

OpenCV几何图像变换(10)透视变换函数warpPerspective()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 warpPerspective 函数使用指定的矩阵对源图像进行透视变换&#xff1a; dst ( x , y ) src ( M 11 x M 12 y M 13 M 31 x M 32 y M 33 , M…

算法练习题04:连续子字符串出现的次数

题目描述 在2021年11月6日&#xff0c;中国战队EDG&#xff08;Edward Gaming&#xff09;在冰岛雷克雅未克举行的《英雄联盟》全球总决赛中&#xff0c;击败了韩国战队DK&#xff08;DWG KIA&#xff09;&#xff0c;首次捧起召唤师杯。 虽然两支队伍在比赛中表现都很出色&a…

Spring Boot应用中集成与使用多数据源

Spring Boot应用中集成与使用多数据源 1. 前言 通过定义和使用多个数据源&#xff0c;能在Spring Boot应用中实现更复杂的数据管理场景&#xff0c;比如读写分离、数据冗余等。 2. 准备工作 环境准备&#xff1a;确保已经准备好Spring Boot的开发环境。数据库准备&#xff…

mlp学习

MLP是Multi-Layer Perceptron的缩写&#xff0c;中文通常翻译为“多层感知器”。它是一种前馈神经网络&#xff0c;由多个神经元层组成&#xff0c;包括一个输入层、多个隐藏层和一个输出层。MLP是深度学习的基础&#xff0c;广泛应用于各种机器学习和人工智能任务中。 MLP的主…

必备工具:2024四大视频压缩神器推荐!

随着视频质量的不断提高&#xff0c;文件大小也变得越来越大&#xff0c;这给存储和分享带来了不小的挑战。今天&#xff0c;我们就来一起探索几款优秀的视频压缩工具&#xff01; 福昕视频压缩大师 直达链接&#xff1a;www.foxitsoftware.cn/shipinyasuo/ 福昕视频压缩大师…

两个月冲刺软考——SQL基础:排序、分组和聚合函数的实用指南

1.涉及到的部分基本语法 1.1 ORDER BY 与 GROUP BY ORDER BY用于对查询结果进行排序&#xff1b;默认是升序&#xff08;ASC&#xff09;&#xff0c;可以指定降序&#xff08;DESC&#xff09;。 GROUP BY用于将数据按照一个或多个列进行分组&#xff1b;通常与聚合函数&am…

将每一列的每 3 行的格值拼进一个格子

某 csv 文件的第 3 列是特殊的字符串&#xff1a;两端有引号&#xff0c;被拆分为多行&#xff08;相当于用回车分隔&#xff09;。 id,name,description,age 23,Anna,"Self-made Chef Shoemaker",23 1,Lily,"One Way go far",24 2,Joe,"Go aHead&quo…

element input限制输入框只能输入数字

element input输入框只能输入数字 <el-input v-model"value" onkeypress"return( /[\d]/.test(String.fromCharCode(event.keyCode)))"></el-input>限制不能输入中文 <el-input input"formData.stationCode formData.stationCode.r…

长视频平台:谁都想成为「爆款制造机」

【潮汐商业评论/ 原创】 “今晚下班回家&#xff0c;我要先追优酷更新的《边水往事》&#xff0c;再补爱奇艺的《九部检察官》&#xff0c;还有腾讯视频新上线的脱口秀……”对于Chloe来说&#xff0c;没有什么比下班回家看剧更放松的。 “为了追这些剧&#xff0c;我最近把优…

数据结构(一)——顺序表和单向链表(一对一)

数据结构&#xff1a; 1.衡量一个程序是否优秀&#xff1a; 1.时间复杂度&#xff1a; 数据量增长与程序运行时间的比例关系以函数描述称为时间渐进复杂度函数,简称时间复杂度 O(c) > O(logn) > O(n) > O(nlogn) > O(n^2) > O(n^3) > O…