vue2知识点以及面试总结

最近看了一个大佬的vue全部解析课程,感觉自己以前啥也不懂,所以趁现在在还有余热,赶紧整理份总结,以及网上比较热的面试题来写一下自己的答案,不说了,先上个大图。
在这里插入图片描述

vue基础问题
1,v-show和v-if区别
1.v-show是通过CSSdisplay控制显示和隐藏的
2.v-if组件的渲染和销毁而不是显示和隐藏
3.频繁切换i显示状态用v-show否则v-if
2,v-for中使用key
1.必须使用key,且不能是通过index和random
2.diff算法中通过tag和key来判断,是否为同一个vnode节点
3.减少渲染次数,提升性能
3,vue组件如何通信
1.父子组件props和$emit
2.自定义事件event.$no event.$off event.$emit
3.vuex
4,双向绑定数据v-model实现原理
1.input元素的value=this.name
2.绑定input事件this.name=$event.target.value
3.data更新触发re-render
5,computed和watch的不同
大图中已做解释
6,动态组件和异步组件的使用
大图中已做解释
7,vue的高级特性
大图中已做解释
8,vue2的一些生命周期的用法
1.created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
2.mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
3.beforeDestory: 清除定时器,清除事件,如果有需要可以清除页面的数据
9,vue2和vue3的生命周期
1.vue2:beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed
2.vue3:setup(),onBforeMount, onMounted, onBforeUpdate, onUpdated, onBforeUnmount, onUnmounted
3.vue3的setup()相当于vue2的beforeCreate,created,这些周期名和作用一定要记清楚,不能说错了
10,vuex的问题
这里主要会问到 action中可做异步处理mutation不可以,action中需要调用mutation中的方法修改数据,其他的看大图就行了
11,vue中性能优化 !
十二,vue中性能优化
  合理使用v-show和v-if、合理使用computed、v-for时候使用key,避免于v-if同时使用、合理使用异步组件、合理使用keep-alive、
  data层级不能太深、图片懒加载、使用SSR
 SRR: 
 1. 基于nodejs  serve服务环境开发,所有html代码在服务端渲染,
 2. 数据返回给前端,然后前端进行“激活”,即可成为浏览器识别的html代码,
 3. 首次加载更快,有更好的用户体验,有更好的seo优化,因为爬虫能看到整个页面的内容,
    如果是vue项目,由于数据还要经过解析,这就造成爬虫并不会等待你的数据加载完成,所以其实vue项目的seo体验并不是很好	
vue原理问题
12,Object.defineProperty和new Proxy对比 !
Proxy使用上比Object.defineProperty方便的多。
Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
vue中,Proxy在调用时递归,Object.defineProperty在一开始就全部递归,Proxy性能优于Object.defineProperty(在大量数据或深层
次嵌套中,Proxy不需要全部遍     历数据,自然能更快的加载数据,呈现页面)。
对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。
13,为什么用vdom
1.JS操作真实DOM的代价过大,这里vdom为了解决浏览器性能问题,这里可以看下大佬关于[vdom](https://www.jianshu.com/p/af0b398602bc)的详细描述
2.把dom树转化为JS来操作,因为JS的运行非常快
3.新旧vnode对比只更新需要更新的部分,其他的不操作,避免重复操作带来的性能和内存上的占用
4.可以通过下载运行http://github.com/snabbdom/snabbdom9 来查看vdom工作过程
具体就是用h()函数生成的一个代码块
    h("div#container.two.classes", { on: { click: someFn } }, [
	  h("span", { style: { fontWeight: "bold" } }, "This is bold"),
	  " and this is just normal text",
	  h("a", { props: { href: "/foo" } }, "I'll take you places!"),
	]);
14,diff算法
1.diff算法对比dom树时,能够提升dom节点的对比速度,当数据或视图变化时,能够更快更新,提升性能
2.优化时间复杂度到O(n),需要用到element和key,只比较同一级时,element或者key不相同,就把旧的元素的删掉,用心的替换掉
3sameVnode.patchVnode,addVnodes,removVnods,updateChildren这几个是比较重要的函数需要记住
15,模板编译是什么
1.首先模板编译中会用到with语法,改变自由辩论的查找规则,当中obj熟悉来查找,找不到对应属性会报错
2.vue的vue template complier 将模板编译为render函数 (将html元素编译为js代码来执行)
3.执行render函数生成vnode
4.有了vnode就可以执行一下的patch和diff了
      <div>
	    <header>
	      <h1>I'm a template!</h1>
	    </header>
	    <p v-if="message">{{ message }}</p>
	    <p v-else>No message.</p>
	  </div>
	function anonymous() {
	  with(this){return _c('div',[_m(0),(message)?_c('p',[_v(_s(message))]):_c('p',[_v("No message.")])])}
	}
	// 将html代码编译为函数形式再返回,类似于vdom用的h()函数进行编译,而_c,_m,_v这些都是创建元素或者文本的基础用法是缩写,有兴趣的可以了解下

16,组件渲染更新过程
1.解析模板为render函数
2.触发响应式,监听data属性的getter和setter
3.执行render函数,生成vnode,patch(elem,vnode)
17,组件渲染更新过程
1.修改data,触发getter
2.重新执行render函数,生成newVnode
3.执行patch(vnode,newVnode)函数
18,vue组件的异步渲染
异步渲染和熟悉的节流函数最终目的是一致的,将多次数据变化所引起的响应变化收集后合并成一次页面渲染,从而更合理的利用机器资源,提升性能与用户体验。
所以vue使用异步渲染,多次修改data就值渲染一次页面,避免了多次渲染页面的性能消耗
还有就是$nextTick()函数就是页面异步渲染完成后做的一个回调,有异步夹在完成的需求可以在这里边操作

最后复制一下vue的Object.defineProperty的源码简单分析下

  function defineReactive$$1 (obj,key,val,customSetter,shallow) {
    // obj对象,key健名,val值
    var dep = new Dep();
    //getOwnPropertyDescriptor()方法返回指定对象上一个自有属性对应的属性描述符
    var property = Object.getOwnPropertyDescriptor(obj, key);
    // .configurable 当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为true。
    if (property && property.configurable === false) {
      return
    }
    // cater for pre-defined getter/setters 预定义的 getter/setter 方法
    var getter = property && property.get; // 获取该属性的访问器函数(getter)
    var setter = property && property.set; // 获取该属性的设置器函数(setter)
    if ((!getter || setter) && arguments.length === 2) {
      val = obj[key];
    }
    var childOb = !shallow && observe(val);
    Object.defineProperty(obj, key, {
      enumerable: true, // 属性在对象中可见
      configurable: true, // 属性在对象中修改或删除
      get: function reactiveGetter () {
        // var value = getter ? getter.call(obj) : val;
        // if (Dep.target) {
        //   dep.depend();
        //   if (childOb) {
        //     childOb.dep.depend();
        //     if (Array.isArray(value)) {
        //       dependArray(value);
        //     }
        //   }
        //  }
        return value
      },
      set: function reactiveSetter (newVal) {
        var value = getter ? getter.call(obj) : val;
        /* eslint-disable no-self-compare */
        // 新值等于原值时候,不更新
        if (newVal === value || (newVal !== newVal && value !== value)) {
          return
        }
        /* eslint-enable no-self-compare */
        if (customSetter) {
          customSetter();
        }
        // #7981: for accessor properties without setter
        if (getter && !setter) { return }
        if (setter) {
          setter.call(obj, newVal);
        } else {
          val = newVal;
        }
        childOb = !shallow && observe(newVal);
        dep.notify();
      }
    });
  }
  // observe()函数 起到一个循环递归的作用
  function observe (value, asRootData) {
    这里判断如果不是对象或者类型是VNode类型的话,不执行
    if (!isObject(value) || value instanceof VNode) {
      return
    }
    var ob;
    // 尝试为一个值创建一个响应式实例,如果成功判断成功,返回新的响应式,如果值已经有一个响应式,返回现有的响应式。
    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    // hasOwn检查一个对象属性是否具有。
    // var hasOwnProperty = Object.prototype.hasOwnProperty;
    // function hasOwn (obj, key) {
    //    return hasOwnProperty.call(obj, key)
    // }
    // Observer在这里应该是被定义为一个观察者类,或者说是能够触发getter和setter的响应式
      ob = value.__ob__;
    } else if (
      shouldObserve &&
      !isServerRendering() &&
      (Array.isArray(value) || isPlainObject(value)) &&
      Object.isExtensible(value) &&
      !value._isVue
    ) {
      // shouldObserve 判断是否为观察者
      // isServerRendering()这需要延迟评估,因为在//vue-server-renderer 设置 vue _ env 之前可能需要 vue
      //  isExtensible()方法判断一个对象是否是可扩展的
      // _isVue初始化时候已经设置为true
      ob = new Observer(value);
    }
    if (asRootData && ob) {
      ob.vmCount++;
    }
    return ob
  }
  // 对象的属性键转换为 getter/setter,getter/setter 收集依赖关系并分发更新,创建响应式
  // Observer 中的内容先不看,只看this.walk()中的
  var Observer = function Observer (value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    def(value, '__ob__', this);
    if (Array.isArray(value)) {
      if (hasProto) {
        protoAugment(value, arrayMethods);
      } else {
        copyAugment(value, arrayMethods, arrayKeys);
      }
      this.observeArray(value);
    } else {
      this.walk(value);
    }
  };

  // 为每一个对象中的键创建一个getter和setter的响应式
  Observer.prototype.walk = function walk (obj) {
    var keys = Object.keys(obj); // 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序
    // 和正常循环遍历该对象时返回的顺序一致 (返回一个由key键组成的数组)
    for (var i = 0; i < keys.length; i++) {
      defineReactive$$1(obj, keys[i]);
    }
  };

// 1.首先页面初始中,源码已经执行了defineReactive$$1,那么初始化的每个数据响应式
// 2.当我们要设置一个var obj = { a: 1}对象添加一个obj.a.b = 1时,触发defineReactive$$1,经过observe(val)函数时发现val是个对象,
// 继续执行Observer.prototype.walk()方法,再次触发defineReactive$$1,将属性b也进行了响应式的绑定
// 这里就说明了我们之前讲的Object.defineProperty的缺点在一开始就将数据全部递归,大量嵌套数据的遍历会严重影响性能
总结
只是做了一个总结,算是面试题的一个答案。既然时面试到底还是考试,如果你东西都记不清,还想拿高分吗,所以不用想了,先记在脑子里再说。
只有产生兴趣了,才会深入研究里边的内容
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值