2024年1月10日

1 Pinia和Vuex的区别

  1. 支持选项式api和组合式api写法

  2. pinia没有mutations,只有:state、getters、actions( state是一个对象返回一个对象和组件的data是一样的语法)

  3. pinia分模块不需要modules(之前vuex分模块需要modules)

  4. TypeScript支持很好

  5. 自动化代码拆分

  6. pinia体积更小(性能更好)

2 vue2的组件通信

  • 父子组件之间的通信

  • 兄弟组件之间的通信

  • 祖孙与后代组件之间的通信

  • 非关系组件间之间的通信

  1. 通过 props 传递 //父传子

  2. 通过 $emit 触发自定义事件 //子传父

  3. 使用 ref //子传父

  4. EventBus //兄弟组件传值

  5. $parent 或$root //兄弟组件传值(共同祖辈)

  6. attrs 与 listeners

  7. Provide 与 Inject //祖先传递数据给子孙

  8. Vuex //状态管理工具

3 js事件循环机制

  1. 调用栈(Call Stack):用于存储函数调用的信息,包括函数的参数、局部变量和返回地址等。

  2. 任务队列(Task Queue):用于存储待处理的任务,包括宏任务和微任务。 3.事件循环(Event Loop):不断检查任务队列中是否有任务可执行,如果有则按优先级取出任务放入调用栈执行。

事件循环的工作过程如下:

  1. 执行栈中现有的代码。

  2. 当遇到异步任务(如定时器、网络请求等)时,将其放入任务队列中,并继续执行栈中现有的代码。

  3. 当栈中现有的代码全部执行完毕后,事件循环检测到任务队列中存在任务,就按照以下规则处理:

  • 如果有微任务,就先执行所有的微任务。

  • 微任务执行完毕后再去检查宏任务,执行一个宏任务。

  • 重复上述步骤,直到任务队列中没有任何任务。

  1. 当任务队列中的所有任务都处理完毕后,JavaScript线程就空闲出来了,可以执行其他任务或等待新的任务。

事件循环是一个循环的过程,会不断地检查任务队列和执行栈,直到所有任务都处理完毕。同时,js的执行是单线程的,即所有任务都是在主线程中执行,无法利用多线程并发执行。

主线程读取JS代码,此时为同步环境,形成相应的堆和执行栈,当主线程遇到异步操作的时候,将异步操作交给对应的API进行处理,当异步操作处理完成,推入任务队列中,主线程执行完毕后,查询任务队列,取出一个任务,并推入主线程进行处理,重复步骤以上步骤,就称之为事件循环(任务队列中又分为宏任务和微任务)

4 vue中nextTick()和setTimeout()

在Vue中,nextTick()方法会先于setTimeout()方法执行。

nextTick()方法是同步执行的,它将回调函数放入一个任务队列中,然后在当前任务完成后立即执行回调函数。而setTimeout()方法是异步执行的,它不会等待当前任务完成,而是在指定的时间后执行回调函数。

在Vue中使用nextTick()可以确保所有的渲染任务都已经完成,而DOM元素已经被更新。这种机制在处理DOM操作和组件通信时非常有用,因为它可以保证回调函数在DOM更新之后执行。

因此,如果在Vue组件中使用nextTick()方法,回调函数将在DOM更新完成后立即执行,而使用setTimeout()方法的回调函数则可能在DOM更新之前执行。所以nextTick()方法会先于setTimeout()方法执行。

5 vue路由懒加载

{  path: '/user/:id',  component: () => import('@/views/User.vue') }

在上面的示例中,User.vue组件将会在访问/user/:id路由时才被加载和创建实例。

另外,还可以使用async关键字修饰import语句来实现异步加载组件

{
path: '/user/:id',
component: async () => await import('@/views/User.vue')
}

使用异步加载时,需要在组件的路由配置中添加meta属性,用来在异步加载时传递元数据。示例代码如下:

{
path: '/user/:id',
component: async () => await import('@/views/User.vue'),
meta: { title: 'User' }
}

在异步加载时,还可以传递参数给组件,示例代码如下:

{
path: '/user/:id',
component: function (resolve) {
import('@/views/User.vue').then((module) => {
 resolve(module.default)
})
},
meta: { title: 'User' }
}

在上面的示例中,通过import()函数动态导入组件,并使用.then()方法处理导入成功后的结果,然后使用resolve()方法将组件对象传递给路由组件的懒加载函数。

6 async和await的区别

  1. async是一个修饰符,用于标记一个函数为异步函数。一个异步函数可以使用await关键字暂停执行,等待异步操作的结果。而await只能在异步函数中使用。

  2. 异步函数返回的是一个Promise,当异步函数中包含await时,会等待异步操作的结果,然后将结果返回给调用者。如果异步函数中发生了异常,会将异常抛给调用者

7 闭包

闭包是指一个函数能够访问并操作其外部函数作用域中的变量,即使在外部函数已经执行完毕并返回之后,这些变量仍然能够被内部函数访问。 具体来说,当一个函数内部定义了另一个函数,并将该内部函数返回或赋值给一个变量时,就形成了一个闭包。内部函数可以访问外部函数的变量和参数,以及它自身的作用域中的变量,但是外部函数无法访问内部函数的变量和参数。 闭包的一个常见用途是创建私有变量和私有函数。由于内部函数可以访问外部函数的变量,但外部函数无法访问内部函数的变量,因此可以将变量定义在外部函数中,并通过内部函数来操作这些变量,从而实现对变量的封装和保护。

8 js中深拷贝和浅拷贝

浅拷贝是指创建一个新对象,将原对象的可枚举属性复制到新对象中,新对象和原对象共享同一类型的直接子属性。如果原对象的属性值是基本类型,则直接复制该属性值;如果原对象的属性值是指针类型(例如对象、数组等),则新对象和原对象的对应属性值仍指向同一块内存地址。

深拷贝是指创建一个新对象,将原对象的可枚举属性复制到新对象中,并且如果原对象的属性值是指针类型,则递归地对属性值进行深拷贝,使新对象和原对象互不影响,各自拥有独立的直接子属性。

浅拷贝的实现方式:

  1. 使用Object.assign()方法:

Object.assign(target, source1, source2, ...);

  1. 使用扩展运算符(...):

const copy = { ...source };

  1. 使用数组的slice方法:

const copy = arr.slice();

深拷贝的实现方式:

  1. 使用递归:

function deepCopy(obj) { 
    if (obj === null || typeof obj !== 'object') { 
        return obj; 
    } 
    let copy; 
    if (Array.isArray(obj)) {
        copy = obj.map(item => deepCopy(item));
    } else {
        copy = {}; 
     Object.keys(obj).forEach(key => { copy[key] =                  deepCopy(obj[key]); }); 
    }
    return copy; 
}

  1. 使用序列化和反序列化:

const copy = JSON.parse(JSON.stringify(obj));
  1. 使用第三方库,如lodash的_.cloneDeep方法:

const copy = _.cloneDeep(obj);

你可能感兴趣的:(前端,前端框架)