vue2和vue3底层原理+两道面试题

vue2使用Object.defineProperty监听对象属性变化,不能监听新增属性。

vue3利用Proxy实现数据绑定

vue2 利用defindeProperty实现数据绑定

defineProperty基础使用:

Object .defineproperty( obj,prop,descriptor) 限制对对象的操作

1.obj :要修改属性的对象

2.prop:要修改的属性

3.descriptor:对这个属性制定的一些规则

let obj4 = {
neme:“111”
}
Object .defineproperty( obj4 ,'age',{
value :21,	//默认值
writable:true,//是否允许修改,false  不可以修改
enumerable:true,///是否允许被遍历,false 不允许被修改
configurable:true,//配置文件是否被修改
})
descriptor 详解:

函数的第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符和存取描述符

value和writable 是数据描述符(这几个的配置的具体含义我们下面讲)

set和get 是存取描述符

enumerable和configurable 是每次设置都可以使用的,通用描述符

前两个二选一,通用描述符每次都可以使用。

(重点)set和get这也是vue2.0前observe(观察对象属性)的实现原理

存取描述符

get  属性需要提供getter 的方法,如果没有getter 则为undefinde。该方法返回值被作为属性值,默认为undefinde

 当获取该属性时,执行get函数,属性值就是get函数的返回值,如下

let obj = {}
Object.defineProperty(obj, 'name', {
	configurable: true,
	enumerable: true,
	get: function () {
		console.log(`你访问了obj.name属性哦`);
		return 'tom';
	}
})
console.log(obj.name)

 set属性需要提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。

当对象的属性修改是调用set 函数,例如

let obj = {}
Object.defineProperty(obj, 'name', {
	configurable: true,
	enumerable: true,
	set: function (val) {
		console.log(`设置obj.name的值为:${val}`)
	}
})
obj.name = 'aaa'//
console.log(obj.name)

于是,我们可以利用Object.defineProperty的特点,做各种各样的事。其中赫赫有名的就是Vue2中的响应式数据系统,就是通过Object.defineProperty实现的!原理很简单,就是通过setget监控数据变化,当数据发生变化时,可通知页面做update等操作!

我们将对象属性监听封装

let observe = (obj) => {
        //   我们有一个对象 obj,我们希望他里面所有的属性改变的时候-我们能监听到
        // 我们遍历这个对象所有 属性,通过defineProperty的set 来监听
        Object.keys(obj).forEach((key) => {
          // 遍历了obj 的key  和  val
          let val = obj[key];
          // 监听属性的get和set
          Object.defineProperty(obj, key, {
            get() {
              console.log("拦截到正在获取属性:" + key);
              // 返回对应的value
              return val;
            },
            set(newVal) {
              console.log("拦截到正在修改属性:" + key);
              // 设置对应的value
              val = newVal;
            },
          });
        });
      };

使用

         let obj = { name: "zhangsan", age: 18 };
      observe(obj);
      obj.name = "lisi";
      console.log(obj.name);

....但是这种监听,用到数组上有一些缺点....

let list = [1,2,3,4];
observe(list);
console.log(list[0]) // 拦截到正在获取属性:0
list[0] = 2; // 拦截到正在修改属性:0

list[6] = 6; // 无法拦截...
list.push(3); // 无法拦截...

可以看到,通过索引去访问或修改已经存在的元素,是可以拦截到的。如果是不存在的元素,或者是通过push等方法去修改数组,则无法拦截。

正因为如此,vue2在实现的时候,通过重写了数组原型上的七个方法(push、pop、shift、unshift、splice、sort、reverse)来解决(具体可以看vue/src/core/observer/array.js。

vue3利用proxy实现数据绑定

和defineProperty类似,功能几乎一样,用法不同

  1. defineProperty是改变原有对象

  2. proxy是新建一个代理对象

  3. defineProperty只能监听某一属性不能设置去全对象监听;

  4. 如果需要全对象监听则需要递归修改原对象相关属性

    1. 我们上面只是简单的实现。为什么要递归,因为对象的属性 有可能也是个属性

  5. 且defineProperty是对象的方法 数组无法监听;proxy可以对数组进行监听

Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改。这个词的原理为代理,在这里可以表示由它来“代理”某些操作,译为“代理器”。

语法:const p = new Proxy(target, handler)

参数说明:

  • target要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

  • handler一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

 对象拦截封装成函数
   let observe = (person) => {
        let personProxy = new Proxy(person, {
          get(target, key) {
            console.log("正在获取属性", key);
            //target 是 prerson
            //返回person的key
            return target[key];
          },
          set(target, key, val) {
            console.log("正在设置属性", key);
            //设置 persion 的key
            target[key] = val;
            return true;
          },
        });
        return personProxy;
      };

面试题:

vue2 和vue3底层实现原理?

两个版本的使⽤⽅法虽然在表⾯上没有太⼤的⼀个区别,但是在他的底层⽅⾯去看的话区别还是很⼤的.

vue2 的双向数据绑定是利⽤ES5 的⼀个 API ,Object.definePropert()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。
vue3 中使⽤了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽
实现对数据的监控。

vue2和vue3 的响应式原理区别?

 这⾥是引相⽐于vue2版本,使⽤proxy的优势如下
1.defineProperty只能监听某个属性,不能对全对象监听
可以省去遍历、闭包,递归等内容来提升效率(直接绑定整个对象即可)
2.可以监听数组,不⽤再去单独的对数组做特异性操作,通过Proxy可以直接拦截所有对象类型数据的操作,完美⽀持对数组的监听。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值