项目一坨屎 开始技术问
讲一下vue的生命周期的理解,流程?
Vue.js 组件的生命周期是指一个 Vue 实例从创建到销毁的整个过程中,会经历的一系列钩子函数的执行顺序。理解 Vue 组件的生命周期可以帮助开发者在不同阶段执行相应的操作,例如数据初始化、DOM 渲染、事件监听等。下面是 Vue 组件的生命周期钩子函数及其执行顺序:
-
创建阶段(Initialization):
beforeCreate: 实例刚刚被创建,组件的数据观测和事件初始化之前被调用。created: 实例已经创建完成,组件的数据观测和事件初始化已经完成。可以访问数据、方法,但尚未挂载到 DOM 上。
-
挂载阶段(Mounting):
beforeMount: 在挂载开始之前被调用,此时模板编译已经完成,但尚未将模板渲染到页面上。mounted: 实例挂载到 DOM 上后调用,此时组件已经被渲染到页面上,可以访问到 DOM 元素。
-
更新阶段(Updating):
beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。可以在该钩子中进一步修改数据,但不会触发附加的重新渲染。updated: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之后。可以在该钩子中操作 DOM,但要注意避免无限循环的更新。
-
销毁阶段(Destroying):
beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用,可以执行清理操作,如取消定时器、解绑事件等。destroyed: 实例销毁后调用。在这一步,Vue 实例的所有指令都被解绑,所有事件监听器被移除,所有子实例被销毁。组件完全被清理,可以执行一些清理工作。
下图展示了 Vue 组件的生命周期钩子函数的执行顺序:
beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed
理解 Vue 组件的生命周期有助于开发者在不同阶段执行相应的操作,例如在 created 钩子中进行数据初始化,在 mounted 钩子中进行 DOM 操作,等等。同时,也要注意合理地利用生命周期函数,避免出现无意义的操作,提高组件的性能和可维护性。
vue组件间的通信方式?
在 Vue.js 中,组件之间的通信可以通过多种方式实现,包括:
- Props/Events(父子组件通信): 使用 Props 将数据从父组件传递给子组件,通过 Events 在子组件触发事件并将数据传递给父组件。这是最常见的父子组件通信方式。
<!-- Parent.vue -->
<template>
<Child :message="message" @update="updateMessage" />
</template>
<script>
export default {
data() {
return {
message: 'Hello from parent'
};
},
methods: {
updateMessage(newMessage) {
this.message = newMessage;
}
}
};
</script>
<!-- Child.vue -->
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script>
export default {
props: ['message'],
methods: {
sendMessage() {
this.$emit('update', 'Hello from child');
}
}
};
</script>
- on(非父子组件通信): 使用 Vue 实例的
$emit方法在一个组件中触发一个自定义事件,然后在其他组件中使用$on方法监听并响应该事件。这种方式适用于非父子关系的组件之间通信。
// EventBus.js
import Vue from 'vue';
export const EventBus = new Vue();
// ComponentA.vue
<script>
import { EventBus } from './EventBus.js';
export default {
methods: {
sendMessage() {
EventBus.$emit('message', 'Hello from Component A');
}
}
};
</script>
// ComponentB.vue
<script>
import { EventBus } from './EventBus.js';
export default {
data() {
return {
message: ''
};
},
created() {
EventBus.$on('message', (msg) => {
this.message = msg;
});
}
};
</script>
-
Vuex(状态管理): 使用 Vuex 管理应用的状态,将数据存储在全局的 store 中,不同组件通过派发和订阅 actions/mutations 来改变和获取数据。适用于大型应用的状态管理。
-
Provide/Inject(祖先组件向后代组件注入数据): 使用
provide在祖先组件中提供数据,然后在后代组件中使用inject来注入数据。适用于祖先组件向多层嵌套的后代组件传递数据。 -
**refs` 来访问子组件的实例或 DOM 元素。但这种方式只适用于父组件直接访问子组件,不适用于跨级组件通信。
以上是几种常见的 Vue 组件间通信方式,根据具体场景和需求选择合适的方式来实现组件间的通信。
为什么要用pinia不用vuex,说一下区别?
Pinia 和 Vuex 都是 Vue.js 中用于状态管理的工具,但它们有一些区别,下面是它们之间的一些对比:
-
API 设计:
- Vuex 的 API 设计是基于 mutations 和 actions 的,通过提交 mutations 来改变 state,通过 actions 来异步提交 mutations。
- Pinia 的 API 设计是基于 getters、actions 和 mutations 的,与 Vuex 相比更加简洁和直观,使用起来更加灵活。
-
模块化:
- Vuex 支持模块化,允许将 store 拆分为多个模块,每个模块都有自己的 state、mutations、actions 和 getters。
- Pinia 也支持模块化,但与 Vuex 相比更加灵活,支持更多的模块化方式,例如使用
defineStore来定义模块。
-
性能优化:
- Pinia 在底层实现上使用了 Vue 3 的响应式 API,相较于 Vuex 在一些性能方面有所优化,例如更快的初始化速度和更小的 bundle 大小。
- Vuex 在 Vue 2 的基础上实现,对一些复杂场景的性能可能不如 Pinia。
-
TypeScript 支持:
- Pinia 对 TypeScript 有更好的支持,能够提供更好的类型推断和类型安全。
- Vuex 也支持 TypeScript,但相较于 Pinia 在一些类型推断上可能不够完善。
-
响应式原理:
- Pinia 在底层使用了 Vue 3 的响应式 API,这意味着它能够更好地与 Vue 3 的生态系统整合,提供更好的开发体验和性能。
- Vuex 在底层使用了 Vue 2 的响应式 API,虽然也可以在 Vue 3 中使用,但在性能和开发体验上可能不如 Pinia。
总的来说,Pinia 和 Vuex 都是用于状态管理的工具,选择使用哪一个取决于个人偏好、项目需求和团队经验。如果是在 Vue 3 的项目中,且需要更好的性能和类型支持,那么可以考虑使用 Pinia;如果是在 Vue 2 的项目中,或者需要与 Vuex 生态系统紧密集成,那么可以继续使用 Vuex。
讲一下vue的双向绑定的原理?
Vue.js 中的双向数据绑定是指数据的改变会同步更新视图,视图的改变也会同步更新数据,这样就实现了数据和视图之间的双向关联。Vue 的双向绑定主要是通过以下几个步骤实现的:
-
数据劫持(Data Observation): Vue.js 使用了 Object.defineProperty() 方法来劫持(或称为“代理”)对象的属性访问,从而在属性被访问或修改时进行拦截,实现对数据的监听。当数据对象被访问时,Vue 将对其进行监视;当数据对象的属性发生变化时,Vue 将触发更新视图的操作。
-
模板解析(Template Parsing): Vue.js 将模板解析成虚拟 DOM(Virtual DOM),并建立模板中表达式与数据对象之间的映射关系。模板中的插值表达式和指令会被解析成相应的 JavaScript 代码,并被包装成一个 render 函数。
-
编译(Compilation): Vue.js 在编译阶段将模板编译为 render 函数。编译过程中会遍历模板中的所有节点,对节点中的指令和表达式进行处理,生成渲染函数。这个渲染函数的作用是根据数据的变化动态地生成虚拟 DOM,从而更新视图。
-
数据响应(Reactivity): 当数据对象发生变化时,Vue.js 会通过 Object.defineProperty() 或 Proxy 等机制自动触发相应的更新操作。当数据发生变化时,Vue 会通知相关的视图组件进行重新渲染,从而实现数据的响应式更新。
-
视图更新(View Update): 当数据发生变化时,Vue.js 会自动重新计算虚拟 DOM,并通过 diff 算法找出变化的部分,最终更新到实际的 DOM 中。这样就实现了数据变化时视图的自动更新,即实现了双向数据绑定。
总的来说,Vue.js 的双向数据绑定是通过数据劫持、模板解析、编译、数据响应和视图更新等步骤来实现的。这个过程确保了数据与视图之间的同步更新,让开发者可以更方便地操作数据,同时也提高了应用的性能和用户体验。
讲一下vue2和vue3的区别?
Vue.js 3 相对于 Vue.js 2,引入了一些重大变化和改进。下面是 Vue.js 3 相对于 Vue.js 2 的一些主要区别:
-
Composition API: Vue.js 3 引入了 Composition API,提供了一种更灵活、更可组合的方式来组织组件逻辑。相较于 Vue.js 2 的 Options API,Composition API 更加灵活,可以更好地组织和重用逻辑代码,尤其适用于大型复杂组件和可复用逻辑的情况。
-
性能优化: Vue.js 3 对内部的响应式系统进行了优化,提高了性能和效率。Vue.js 3 使用了 Proxy 替代了 Vue.js 2 中的 Object.defineProperty(),使得响应式系统更加快速和稳定。同时,Vue.js 3 引入了静态提升(Static Tree Hoisting)和源码级的优化,提高了渲染性能。
-
Tree-Shaking 支持: Vue.js 3 支持 Tree-Shaking,可以更好地利用模块系统来进行代码优化和剔除未使用的代码,减小包的体积。
-
Typescript 支持: Vue.js 3 对 TypeScript 有更好的支持,提供了更完善的类型定义文件,可以提供更好的类型检查和类型推断。
-
Teleport 和 Suspense: Vue.js 3 引入了 Teleport 和 Suspense 这两个新的特性。Teleport 允许将组件的内容渲染到任意 DOM 节点中,而不受父组件的限制。Suspense 允许在异步组件加载时显示加载中的占位符。
-
Fragments 和 Portals: Vue.js 3 支持 Fragments 和 Portals,允许更灵活地组织组件的结构,并更方便地操作 DOM。
-
全局 API 重命名: Vue.js 3 对一些全局 API 进行了重命名,如
Vue.observable改为Vue.reactive,Vue.set改为Vue.reactive等,以更好地与 Composition API 和响应式系统整合。
总的来说,Vue.js 3 在性能、开发体验、灵活性和功能上都有所提升,使得开发者能够更轻松地构建高性能、可维护和可扩展的应用程序。但需要注意的是,由于 Vue.js 3 引入了一些重大变化,迁移现有的 Vue.js 2 项目到 Vue.js 3 可能需要一些工作,尤其是在迁移 Composition API 和调整全局 API 使用方面。
讲到了diff算法->为什么要用虚拟dom?
使用虚拟 DOM 的主要目的是优化页面的渲染性能和提高开发效率。下面是使用虚拟 DOM 的一些优势:
-
性能优化: 虚拟 DOM 可以在内存中维护一份虚拟 DOM 树,并通过 diff 算法比较前后两个虚拟 DOM 树的差异,然后将差异更新到实际的 DOM 上。这样可以减少直接操作 DOM 带来的性能开销,提高页面的渲染性能。
-
跨平台兼容性: 虚拟 DOM 可以抽象出平台无关的 DOM 结构,使得相同的虚拟 DOM 结构可以渲染到不同的平台上,包括浏览器、移动端和服务器端等。这样可以实现跨平台的组件复用和开发效率的提高。
-
开发效率: 使用虚拟 DOM 可以提高开发效率,因为开发者可以直接操作虚拟 DOM,而不需要关心底层的 DOM 操作细节。同时,虚拟 DOM 可以实现组件级别的更新,使得页面的局部更新更加高效和灵活。
-
组件化开发: 虚拟 DOM 可以与组件化开发结合,使得组件可以封装自己的状态和行为,并通过 props 和 events 来进行通信。这样可以实现组件的高度复用和解耦,提高代码的可维护性和可复用性。
-
优化渲染流程: 虚拟 DOM 可以通过批量更新和异步更新等技术优化渲染流程,减少页面的重绘和重排,提高页面的渲染性能和用户体验。
综上所述,使用虚拟 DOM 可以优化页面的渲染性能、提高开发效率、实现跨平台兼容性和组件化开发,并优化渲染流程,是现代前端开发中的一种重要技术手段。虽然虚拟 DOM 也存在一些缺点,如增加了额外的内存开销和复杂性,但相对于它带来的性能和开发效率的提升而言,这些缺点是可以被接受的。
计算机网络了解的多吗?额
简单问了一下 get和post的区别?
GET 和 POST 是 HTTP 协议中最常用的两种请求方法,它们之间有以下几个主要区别:
-
语义:
- GET:用于从服务器获取资源,通常用于读取数据,不应该对服务器状态产生副作用。
- POST:用于向服务器提交数据,通常用于创建、更新或删除资源,可能会对服务器状态产生副作用。
-
数据传输方式:
- GET:通过 URL 查询参数将数据传输到服务器,数据会附加在 URL 中,可见于 URL 地址栏,有长度限制。
- POST:通过请求体将数据传输到服务器,数据不会附加在 URL 中,不可见于 URL 地址栏,没有长度限制。
-
安全性:
- GET:由于数据暴露在 URL 中,因此不适合传输敏感信息,如密码等,因为 URL 可以被浏览器历史记录、代理服务器等截获。
- POST:由于数据传输在请求体中,相对于 GET 更加安全,适合传输敏感信息。
-
缓存机制:
- GET:可以被缓存,浏览器可以缓存 GET 请求结果,当再次请求相同资源时可以直接从缓存中获取,提高页面加载速度。
- POST:默认情况下不被缓存,每次请求都会发送到服务器,不能从缓存中获取。
-
幂等性:
- GET:幂等的,同一个 GET 请求多次调用不会对服务器产生影响,不会改变服务器状态。
- POST:不幂等的,同一个 POST 请求多次调用可能会对服务器产生不同的影响,可能会改变服务器状态。
总的来说,GET 用于获取数据,数据在 URL 中传输,安全性较低,适合读取数据;而 POST 用于提交数据,数据在请求体中传输,安全性较高,适合更新数据。在选择使用 GET 还是 POST 时,需要根据实际情况和需求来决定。
因为我答了Get 请求的报文中实体部分为空 被深入问了一下 可以在get的body里面放数据传吗(要我从get和post的本质思考)?
讲一下css的盒模型
CSS 盒模型是指在网页布局中,每个元素在页面中所占的空间都可以看作是一个矩形的盒子。这个盒子由四个部分组成:内容区域(Content)、内边距区域(Padding)、边框区域(Border)、外边距区域(Margin)。盒模型定义了这些区域之间的关系,以及各个区域对元素大小的影响。
盒模型包括两种标准:W3C 盒模型(标准盒模型)和 IE 盒模型(怪异盒模型)。它们的主要区别在于计算元素宽度和高度的方式:
-
W3C 盒模型(标准盒模型):
-
元素的宽度和高度只包括内容区域(Content)的尺寸,不包括内边距(Padding)、边框(Border)和外边距(Margin)。
-
元素的总宽度和总高度可以通过 CSS 的 width 和 height 属性设置,这两个属性只设置内容区域的尺寸。
-
-
IE 盒模型(怪异盒模型):
-
元素的宽度和高度包括内容区域(Content)、内边距(Padding)和边框(Border)的尺寸,不包括外边距(Margin)。
-
元素的总宽度和总高度可以通过 CSS 的 width 和 height 属性设置,但这两个属性会设置整个盒子的尺寸,包括内容区域、内边距和边框。
-
在 CSS 中,默认情况下使用的是 W3C 盒模型,可以通过 box-sizing 属性来控制使用哪种盒模型,常见的取值有 content-box(默认值,表示 W3C 盒模型)和 border-box(表示 IE 盒模型)。
盒模型在页面布局中非常重要,掌握盒模型的原理和使用方法可以更好地进行网页布局和样式设计。
讲一下==和===的区别
在 JavaScript 中,== 和 === 都是用来比较两个值是否相等的运算符,它们之间的区别在于比较的严格程度不同:
-
==(相等运算符):==会先进行类型转换,然后再比较两个值是否相等。- 如果两个操作数的类型不同,JavaScript 将尝试将它们转换为相同的类型,然后再进行比较。
- 如果两个操作数的类型相同,就会进行相等比较。
==运算符会进行类型转换,可能会导致一些意想不到的结果,因此不推荐使用。
-
===(严格相等运算符):===不会进行类型转换,而是直接比较两个值的类型和值是否完全相等。- 如果两个操作数的类型不同,直接返回 false,不会进行类型转换。
- 只有在两个操作数的类型和值完全相等时,
===才会返回 true。
下面是一个示例,演示了 == 和 === 的区别:
console.log(5 == "5"); // true,因为 "5" 被转换为数字 5,然后进行比较
console.log(5 === "5"); // false,因为类型不同
console.log(0 == false); // true,因为 false 被转换为数字 0,然后进行比较
console.log(0 === false);// false,因为类型不同
console.log(null == undefined); // true,因为它们被认为是相等的特殊情况
console.log(null === undefined); // false,因为它们的类型不同
总的来说,=== 比 == 更加严格,推荐在进行相等比较时使用 === 运算符,以避免类型转换带来的不确定性。
开始手撕 他也不含糊问我算法了解的多吗? 我说我会写基本的
用栈实现队列?两个栈 分别都进行翻转 没叫我实现代码 画了图说思路
要使用两个栈实现队列,可以采用以下思路:
- 使用两个栈
stack1和stack2分别来模拟队列的入队和出队操作。 - 入队操作时,直接将元素压入
stack1中。 - 出队操作时,首先检查
stack2是否为空,如果不为空,则直接弹出stack2的栈顶元素;如果stack2为空,则将stack1中的所有元素逐个弹出并压入stack2中,然后再弹出stack2的栈顶元素。 - 当
stack2不为空时,说明其中的元素顺序与队列中的顺序相同,可以直接进行出队操作;当stack2为空时,需要将stack1中的元素逆序压入stack2,以保持队列的顺序。
下面是使用 JavaScript 实现的代码示例:
class Queue {
constructor() {
this.stack1 = [];
this.stack2 = [];
}
// 入队操作,直接将元素压入 stack1 中
enqueue(value) {
this.stack1.push(value);
}
// 出队操作
dequeue() {
// 如果 stack2 不为空,则直接弹出栈顶元素
if (this.stack2.length > 0) {
return this.stack2.pop();
}
// 如果 stack2 为空,则将 stack1 中的元素逆序压入 stack2
while (this.stack1.length > 0) {
this.stack2.push(this.stack1.pop());
}
// 再从 stack2 中弹出栈顶元素
return this.stack2.pop();
}
}
// 测试
const queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
console.log(queue.dequeue()); // 1
console.log(queue.dequeue()); // 2
queue.enqueue(4);
console.log(queue.dequeue()); // 3
console.log(queue.dequeue()); // 4
这样就实现了使用两个栈来模拟队列的功能,保持了队列的先进先出特性。
半个小时结束二面
昨天中午面的 现在还没回信 滴滴一定会有感谢信吗!
作者:朱古力ovo
链接:www.nowcoder.com/feed/main/d…
来源:牛客网