vue数据响应式实现

使用Object.defineProperty和ES6的Proxy,这就是进行数据劫持或数据代理。vue3使用的第二种,之前版本使用第一种。
Object.defineProperty
Vue通过设定对象属性的 setter/getter 方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。
该方式存在的问题:无法观察到对象属性的新增或者删除,array的push和shfit是可以观察到的,因为vue对数组的方法做了特殊的处理。
Proxy支持完整的对象的变化观察,缺点就是兼容性不是很好。

参考文章:vue响应式详解

vue的生命周期

beforeCreate->created->beforeMount->mounted->beforeUpdate->updated->beforeDestroy->destroyed
**

vue的通行方式

  • props父组件传参至子组件
  • $emit()子组件发事件至父组件
  • $parent组件直接调用父组件实例
  • $children子组件直接调用父组件
  • ref挂在实例,调用组件实例
  • Event Bus 实现跨组件通信: Vue.prototype.$bus = new Vue ,bus.$on监听事件,bus.$emit()发送事件,便于全局跨组件事件通信
  • attrs,listeners 一般用于封装组件的集成父组件参数和事件
  • Provide、inject一般用于封装组件中夫子组件参数的共享


vue路由原理

vue-router 有 3 种路由模式:hash、history、abstract,前两种浏览器使用,最后一种node使用
hash模式
location.hash获取的就是url中#后面的部分

  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送
  • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
  • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
  • 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)

history模式
HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState()history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:

  1. window.history.pushState(null, null, path);
  2. window.history.replaceState(null, null, path);

history 路由模式的实现主要基于存在下面几个特性:

  • pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
  • 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

Webpack 层面的优化

  • Webpack 对图片进行压缩———-先引入npm install image-webpack-loader —save-dev,然后在 webpack.config.js 中配置
  • 减少 ES6 转为 ES5 的冗余代码
  • 提取公共代码
  • 模板预编译
  • 提取组件的 CSS
  • 优化 SourceMap
  • 构建结果输出分析
  • Vue 项目的编译优化

keep-alive

keep-alive会缓存包裹组件的vnode,keep-alive作为父组件,缓存包裹的子组件vnode,在需要渲染的时候,再把对应的vnode渲染,就可以保存当前页面的状态了。

  • 提供 includeexclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
  • 对应两个钩子函数 activateddeactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

监听子组件生命周期

@hook

  1. <Child @hook:mounted="doSomething" ></Child>

Vue2.x和Vue3.x渲染器的diff算法分别说一下

简单来说,diff算法有以下过程
同级比较, 再比较子节点,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除),
比较都有子节点的情况(核心diff)递归比较子节点
正常·Diff两个树·的时间复杂度是O(n^3),但实际情况下我们很少会进行跨层级的移动DOM,所以Vue将Diff进行了优化,从O(n^3) -> O(n),只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较
Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。
_Vue3.x借鉴了_ivi算法和 inferno算法 在创建VNode时就确定其类型,以及在mount/patch的过程中采用位运算来判断一个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升。 该算法中还运用了动态规划的思想求解最长递归子序列。

移动端高分屏1px问题

https://juejin.cn/post/6844903877947424782

JavaScript原理题

https://juejin.cn/post/6844903891591495693#heading-6

算法问题

https://juejin.cn/post/6900698814093459463