1. ref和reactive 的区别
1.数据类型不同
ref用于包装JS的任意对象(基本数据类型+对象),而reactive用于包装对象和数组等复杂类型的数据。
2. 使用方式不同:
如果将一个对象赋值给 ref,那么这个对象将通过reactive转为具有深层次响应式的对象
ref需通过
.value
访问 reactive可以直接访问该对象的属性或方法3: 原理:
如果将一个对象赋值给 ref,那么这个对象将通过reactive转为具有深层次响应式的对象
而reactive响应式的原理是建了一个被Proxy代理的对象,Proxy里面代理了各种操作,在读取的时候触发track函数,在写入的时候触发trigger函数。
ref的本质就是实例化了RefImpl类得到了一个对象,访问这个对象的value属性时触发track,设置这个对象的value属性时触发trigger
4. 使用原则:
若需要一个响应式对象,且层级较深,推荐使用 reactive
2. watch和effectWatch的区别
1. watch是惰性执行,也就是只有监听的值发生变化的时候才会执行(除非配置immediate参数,立即执行,以及深层次监听),但是watchEffect不同,watchEffect在组件初始化时会立即执行一次,用来收集依赖。
2. watch需要传递监听的对象(数据源可以是响应式引用(ref)、计算属性(computed)或者是一个返回响应式值的函数),watchEffect不需要它会自动追踪函数内部使用的响应式数据
3.
effectWatch
更适合用来自动响应副作用,特别是在你不关心具体的变化细节时
3. 组合式api和选项式api的区别
选项式 API: 的逻辑组织是基于组件的选项(
data
,methods
,computed
),使得跨多个选项的逻辑复用变得困难。这可能导致组件逻辑的耦合和复杂性增加,逻辑复杂代码多了不好阅读组合式API: 不同组件之间复用逻辑变得更加直观和灵活,便于阅读和维护
4. 回流和重绘是什么是怎么处理的
重绘:当元素样式发生改变,但不影响其几何属性的时候,浏览器只需要重新绘制这个元素,这个过程被称为重绘
回流: 当页面布局和几何属性发生变化,导致部分或全部元素的尺寸、位置、结构发生改变时,浏览器需要重新计算元素的几何属性和页面的布局,这个过程被称为回流。
回流必将引起重绘,而重绘不一定会引起回流
优化: 合并多次 DOM 和样式修改的优势,减少回流和重绘的次数,通过修改元素的类而不是直接操作样式
使用 CSS3 的 transform 和 opacity 属性来替代使用 top、left 等位置和尺寸相关的属性,因为 transform 和 opacity 不会引起回流。
尽可能在DOM树的末端进行操作,避免对整个页面进行回流
尽量使用css3动画来替代使用js实现的动画效果
5. v-model vue2和vue3的区别
单向数据流,父组件传给子组件的数据,子组件只能展示,不能修改,如果需要修改则需要emit事件让父组件修改
v-model 用于实现数据的双向绑定,仅可用于
<input>
、<select>
、<textarea>
和组件。Vue 2 中的
v-model
只支持一个双向绑定的属性(默认是value
),并通过input
事件来更新父组件的数据。(默认绑定value属性和input事件)Vue 3 引入了更灵活的
v-model
机制,支持多个v-model
绑定,支持自定义绑定属性名(modelValue
),并将事件名称更改为update:modelValue
,使得组件的双向绑定更加灵活和语义化。【默认绑定modelValue
属性和update:modelValue
事件】子组件:
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
defineProps(['modelValue']) defineEmits(['update:modelValue'])
6. 如何判断object为空
常用:
1. Object.keys(obj).length === 0
2. JSON.stringify(obj) === '{}'
3. for in 判断
4. Reflect.ownKeys(obj).length === 0 (万能)
回答:
常用的有三种方法:
Object.keys(obj)
返回一个包含对象所有可枚举属性属性名的数组。如果这个数组的长度为0,则说明对象是空的- 将对象转换为 JSON 字符串,然后判断是否为
"{}"
来判断是否为空对象。- 使用
for...in
循环遍历对象的可枚举属性(包括原型链上的属性)。如果没有任何属性被遍历,说明对象为空。但这些方法都适用于判断普通对象为空的情况。如果对象是
null
或undefined
,需要先判断防止出现错误。const obj = null; if (obj && Object.keys(obj).length === 0) { console.log('Object is empty'); }
特殊情况:
以上所有方法都处理不了const obj = {[Symbol('a')]: 1}这种情况,所以更严谨的办法是 Reflect.ownKeys(obj).length === 0
理解:
for in
const obj = {};
let isEmpty = true;
for (let key in obj) {
// 使用 obj.hasOwnProperty(key) 判断该属性是否是对象自身的属性(不包括从原型链继承的)
if (obj.hasOwnProperty(key)) {
isEmpty = false;
break;
}
}
if (isEmpty) {
console.log('Object is empty');
}
{[Symbol('a')]: 1}
是一个使用 计算属性名 和 Symbol 创建的对象
- 计算属性名:
{ [key]: value }
这种形式,方括号内的key
是表达式,它的值会被计算出来并用作对象的属性名。 - Symbol 是 ES6 引入的一种数据类型,它用于生成一个唯一的标识符。在这里,
Symbol('a')
会生成一个唯一的符号。 - 因此,
{[Symbol('a')]: 1}
实际上是一个对象,它有一个属性,属性名是一个唯一的Symbol('a')
,值为1
。
Reflect.ownKeys()
是一个非常合适的选择!它可以返回对象的所有自身属性的键,包括字符串类型的键和 Symbol
类型的键。所以,想检查一个对象是否为空,Reflect.ownKeys()
完全可以用于包含 Symbol
的情况。
const obj = {[Symbol('a')]: 1};
// 使用 Reflect.ownKeys() 获取对象的所有属性(包括 Symbol 和字符串类型的属性)
if (Reflect.ownKeys(obj).length === 0) {
console.log('Object is empty');
} else {
console.log('Object is not empty');
}
Reflect.ownKeys(obj)
返回对象所有的 属性名,包括字符串和Symbol
类型的属性。它不同于Object.keys()
,后者只返回 字符串类型的属性。- 所以,通过判断
Reflect.ownKeys(obj).length === 0
,就可以检查对象是否既没有字符串属性也没有Symbol
属性。
7. 判断对象是否相等
JSON.stringify(obj1) === JSON.stringfy(obj2)
8. TypeScript类型注解
1. 变量的类型注解
let name: string = "Lena"; let age: number = 30; let isStudent: boolean = true;
2. 在函数中,可以为参数和返回值指定类型
const greetUser = (name: string, age: number): string => { return `Hello, my name is ${name} and I am ${age} years old.`; };
3. 作为接口和类型别名
export interface Exam { name: string; age: number; } let employee: Person = { name: 'Lena', age: 25 }