zoukankan      html  css  js  c++  java
  • 2020VUE面试题常考-基础点

    一:对 SPA 单⻚⾯的理解,优缺点是什么?

     SPA( single-page application )仅在 Web ⻚⾯初始化时加载相应的 HTML、JavaScript 和 CSS。⼀旦⻚⾯加载完成,SPA 不会因为⽤户的操作⽽进⾏⻚⾯的重新加载或跳转;取⽽代之的是利⽤路由机制实现 HTML 内容的变换,UI 与⽤户的交互,避免⻚⾯的重新加载。

    优点:

    1)⽤户体验好、快,内容的改变不需要重新加载整个⻚⾯,避免了不必要的跳转和重复渲染;

    2)SPA 相对对服务器压⼒⼩;

    3)前后端职责分离,架构清晰,前端进⾏交互逻辑,后端负责数据处理;

    缺点:

    1)⾸屏(初次)加载慢:为实现单⻚ Web 应⽤功能及显示效果,需要在加载⻚⾯的时候将JavaScript、CSS 统⼀加载,部分⻚⾯按需加载;

    2)不利于 SEO:由于所有的内容都在⼀个⻚⾯中动态替换显示,所以在 SEO 上其有着天然的弱势。

    二:new Vue() 发生了什么?

    1)结论:new Vue()是创建Vue实例,它内部执行了根实例的初始化过程。

    2)具体包括以下操作:

    • 选项合并

    • $children,$refs,$slots,$createElement等实例属性的方法初始化

    • 自定义事件处理

    • 数据响应式处理

    • 生命周期钩子调用 (beforecreate created)

    • 可能的挂载

    3)总结:new Vue()创建了根实例并准备好数据和方法,未来执行挂载时,此过程还会递归的应用于它的子组件上,最终形成一个有紧密关系的组件实例树

    源码地址:src/core/instance/init.js

    三:Vue.use是干什么的?原理是什么?

    核心答案:

    vue.use 是用来使用插件的,我们可以在插件中扩展全局组件、指令、原型方法等。

    1、检查插件是否注册,若已注册,则直接跳出;

    2、处理入参,将第一个参数之后的参数归集,并在首部塞入 this 上下文;

    3、执行注册方法,调用定义好的 install 方法,传入处理的参数,若没有 install 方法并且插件本身为 function 则直接进行注册;

    1) 插件不能重复的加载

    install 方法的第一个参数是vue的构造函数,其他参数是Vue.set中除了第一个参数的其他参数; 代码:args.unshift(this)

    2) 调用插件的install 方法 代码:typeof plugin.install === 'function'

    3) 插件本身是一个函数,直接让函数执行。 代码:plugin.apply(null, args)

    4) 缓存插件。  代码:installedPlugins.push(plugin)

    源码地址:src/core/global-api/use.js

    四:请说一下响应式数据的理解?

    根据数据类型来做不同处理,数组和对象类型当值变化时如何劫持。

    1) 对象内部通过defineReactive方法,使用 Object.defineProperty() 监听数据属性的 get 来进行数据依赖收集,再通过 set 来完成数据更新的派发;

    2) 数组则通过重写数组方法来实现的。扩展它的 7 个变更⽅法,通过监听这些方法可以做到依赖收集和派发更新;( push/pop/shift/unshift/splice/reverse/sort )

    这里在回答时可以带出一些相关知识点 (比如多层对象是通过递归来实现劫持,顺带提出vue3中是使用 proxy来实现响应式数据)

    补充回答:

    内部依赖收集是怎么做到的,每个属性都拥有自己的dep属性,存放他所依赖的 watcher,当属性变化后会通知自己对应的 watcher去更新。

    响应式流程:

    1、defineReactive  把数据定义成响应式的;

    2、给属性增加一个 dep,用来收集对应的那些watcher;

    3、等数据变化进行更新

    dep.depend()  // get 取值:进行依赖收集

    dep.notify() // set 设置时:通知视图更新

    这里可以引出性能优化相关的内容:1)对象层级过深,性能就会差。2)不需要响应数据的内容不要放在data中。3)object.freeze()  可以冻结数据。

    源码地址:src/core/observer/index.js 158

    五:Vue如何检测数组变化?

    数组考虑性能原因没有用defineProperty对数组的每一项进行拦截,而是选择重写数组 方法以进行重写。当数组调用到这 7 个方法的时候,执行 ob.dep.notify() 进行派发通知 Watcher 更新;

    * 重写数组方法:push/pop/shift/unshift/splice/reverse/sort

    补充回答:

    在Vue中修改数组的索引和长度是无法监控到的。需要通过以下7种变异方法修改数组才会触发数组对应的wacther进行更新。数组中如果是对象数据类型也会进行递归劫持。

    说明:那如果想要改索引更新数据怎么办?

    可以通过Vue.set()来进行处理 =》 核心内部用的是 splice 方法。

    // 取出原型方法;
    const arrayProto = Array.prototype  
    // 拷贝原型方法;
    export const arrayMethods = Object.create(arrayProto)  
    // 重写数组方法;
    def(arrayMethods, method, function mutator (...args) { }
    ob.dep.notify()  // 调用方法时更新视图;

    源码地址:src/core/observer/array.js 15

    六:Vue.set 方法是如何实现的?

    核心答案:

    为什么$set可以触发更新,我们给对象和数组本身都增加了dep属性,当给对象新增不存在的属性则触发对象依赖的watcher去更新,当修改数组索引时我们调用数组本身的splice方法去更新数组。

    补充回答:

    官方定义 Vue.set(object, key, value) 

    1) 如果是数组,调用重写的splice方法 (这样可以更新视图 )

    代码:target.splice(key, 1, val)

    2) 如果不是响应式的也不需要将其定义成响应式属性。

    3) 如果是对象,将属性定义成响应式的  defineReactive(ob.value, key, val)

    通知视图更新  ob.dep.notify()

    源码地址:src/core/observer/index.js 202

    七:Vue中模板编译原理?

    核心答案:

    如何将template转换成render函数(这里要注意的是我们在开发时尽量不要使用template,因为将template转化成render方法需要在运行时进行编译操作会有性能损耗,同时引用带有complier包的vue体积也会变大) 默认.vue文件中的 template处理是通过vue-loader 来进行处理的并不是通过运行时的编译。

    1) 将 template 模板转换成 ast 语法树 - parserHTML

    2) 对静态语法做静态标记 - markUp

    3) 重新生成代码 - codeGen

    补充回答:

    模板引擎的实现原理就是new Function + with来进行实现的。

    vue-loader中处理template属性主要靠的是 vue-template-compiler

    vue-loader

    // template => ast => codegen => with+function 实现生成render方法 
    let {ast, render } = VueTemplateCompiler.compile(`<div>{{aaa}}</div>`)
    console.log(ast, render)
    
    // 模板引擎的实现原理 with + new Function
    console.log(new Function(render).tostring())
    // render方法执行完毕后生成的是虚拟 dom
    // with(this){return _c('div',[_s(aaa)])}
    // 代码生成

    源码设置:

    const ast = parse(template.trim(), options) // 将代码解析成ast语法树
      if (options.optimize !== false) {
        optimize(ast, options) // 优化代码 标记静态点 标记树
      }
      const code = generate(ast, options) // 生成代码 

    源码地址:src/compiler/index.js

    八:Proxy 与 Object.defineProperty 优劣对比

    核心答案:

    Proxy 的优势如下:

    1)Proxy 可以直接监听对象而非属性;

    2)Proxy 可以直接监听数组的变化;

    3)Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;4)Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;

    5)Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

    Object.defineProperty 的优势如下:

    兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

    九:Vue3.x响应式数据原理

    Vue3.x改用Proxy替代Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,并且有多达13种拦截方法。并且作为新标准将受到浏览器厂商重点持续的性能优化。

    Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?

    判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。

    监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?

    我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。

    来自VUE中文社区公众号 https://mp.weixin.qq.com/s/60HI-CM1GhqDG5zeTFSOrw

    小凤凰newObject
  • 相关阅读:
    loj#6433. 「PKUSC2018」最大前缀和(状压dp)
    PKUWC2019游记
    10. Regular Expression Matching
    9. Palindrome Number
    8. String to Integer (atoi)
    7. Reverse Integer
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    4. Median of Two Sorted Arrays
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/xiaofenghuang/p/13984187.html
Copyright © 2011-2022 走看看