Proxy和definedProperty

1. Proxy 代理

定义: 用于定义基本操作的自定义行为

Proxy修改的是程序默认形为,就形同于在编程语言层面上做修改,属于元编程

元编程 是指某类计算机程序的编写,这类计算机程序编写或者操纵其它程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作

元编程优点 与手工编写全部代码相比,程序员可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译

大概意思就是 我给你封装了一层,在我操作你的中间加了一段路径,可以用来处理,监听,截停等操作,简称拦路虎

 Proxy 译为代理,可以理解为在操作目标对象前架设一层代理,将所有本该我们手动编写的程序交由代理来处理,生活中也有许许多多的“proxy”, 如代购,中介,因为他们所有的行为都不会直接触达到目标对象

2. Proxy的使用

let p = new Proxy(target, handler);

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

handler:一个对象,其属性是当执行一个操作时定义代理的行为的函数。

let yu = { age: 19, height: 155 }
let p = new Proxy(yu, {
    get: (target, property) => {
        if (property === 'age') {
            return target.age + 6
        } else if (property === 'height') {
            return target.height * 2
        }
     }
})

p.age // 25
yu.age // 19

p.height // 310
yu.height // 155

 

2.1 Handler 对象常用的方法

handler.get上面已经用过了,它其实接受三个参数 get(target, propKey, ?receiver)

  • target 目标对象
  • propkey 属性名
  • receiver Proxy 实例本身

其他的都大同小异,差不多

2.2 可撤消的Proxy

proxy有一个唯一的静态方法 ------- proxy.revocable(target, handler)

这个方法可以用来创建一个可撤销的代理对象
该方法的返回值是一个对象,其结构为: { “proxy”: proxy,“revoke”: revoke }

  1. proxy 表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉
  2. revoke 撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象
const target = { name: 'yu'}
const {proxy, revoke} = Proxy.revocable(target, handler)
proxy.name // 正常取值输出 vuejs
revoke() // 取值完成对proxy进行封闭,撤消代理
proxy.name // TypeError: Revoked

3. proxy和Object.defineProperty

在proxy之前,vue2用的是Object.defineProperty,允许对对象的setter/getter进行拦截,Vue3.0之前的双向绑定是由defineProperty实现的,在3.0重构为 Proxy,那么两者的区别究竟在哪里呢?

定义: Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

上面给两个词划了重点,对象上属性,我们可以理解为是针对对象上的某一个属性做处理的

语法:

Object.defineProperty(obj, prop, descriptor)
 

- obj 要定义属性的对象
prop 要定义或修改的属性的名称或 Symbol

- descriptor 要定义或修改的属性描述符

const obj = {}
Object.defineProperty(obj, "a", {
  value : 1,
  writable : false, // 是否可写 
  configurable : false, // 是否可配置
  enumerable : false // 是否可枚举
})

// 上面给了三个false, 下面的相关操作就很容易理解了
obj.a = 2 // 无效
delete obj.a // 无效
for(key in obj){
  console.log(key) // 无效 
}

3.1 Vue2中的defineProperty

Vue2的双向绑定都是通过 defineProperty 的 getter,setter 来实现的

const obj = {};
Object.defineProperty(obj, 'a', {
  set(val) {
    console.log(`开始设置新值: ${val}`)
  },
  get() { 
    console.log(`开始读取属性`)
    return 1; 
  },
  writable : true
})

obj.a = 2 // 开始设置新值: 2
obj.a // 开始获取属性 

3.2 defineProperty的缺点

Vue在初始化时会对data对象的属性进行数据劫持,但是对于后续新增的属性,Vue无法自动进行响应式处理。Vue 无法探测普通的新增属性

对象

这也就是为什么对象的新增属性为什么不更新

data  () {
  return  {
    obj: {
      a: 1
    }
  }
}

methods: {
  update () {
    this.obj.b = 2
  }
}

这个其实很好理解,我们先要明白 vue 中 data init 的时机,data init 是在生命周期 created 之前的操作,会对 data 绑定一个观察者 Observer,之后 data 中的字段更新都会通知依赖收集器Dep触发视图更新

然后我们回到 defineProperty 本身,是对对象上的属性做操作,而非对象本身

一句话来说就是,在 Observer data 时,新增属性并不存在,自然就不会有 getter, setter,也就解释了为什么新增视图不更新,解决有很多种,Vue 提供的全局$set 本质也是给新增的属性手动 observer

利用delete删除对象的属性,无法被Vue监测到

数组

还有一个就是数组了,由于 JavaScript 的限制,Vue 不能检测以下数组的变动:数组索引设置或者长度改变不是响应式的

var vm = new Vue({
  data: {
    items: ['1', '2', '3']
  }
})
vm.items[1] = '4' // 视图并未更新

解决方法:使用数组的 push()pop()shift()unshift()splice()sort()reverse() 方法来确保数组的变化是响应式的

3.3 总的来说

  • Object.definedProperty 是劫持对象的属性,新增元素需要再次 definedProperty。而 Proxy 劫持的是整个对象,不需要做特殊处理

  • 使用 defineProperty 时,我们修改原来的 obj 对象就可以触发拦截,而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截

相关推荐

  1. proxyObject.defineProperty

    2024-06-18 19:16:03       21 阅读
  2. definePropertyproxy 详解

    2024-06-18 19:16:03       14 阅读
  3. 【Vue】为什么Vue3使用Proxy代替defineProperty

    2024-06-18 19:16:03       33 阅读
  4. VUE3——Proxy API 与VUE2——defineProperty API区别

    2024-06-18 19:16:03       17 阅读
  5. Vue3 用 Proxy API 替代 defineProperty API 的那些事

    2024-06-18 19:16:03       39 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-18 19:16:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-18 19:16:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-18 19:16:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-18 19:16:03       18 阅读

热门阅读

  1. 编程入门笔记:从基础到进阶的探索之旅

    2024-06-18 19:16:03       5 阅读
  2. BSP驱动教程-CAN/CANFD/CANopen知识点总结分享

    2024-06-18 19:16:03       5 阅读
  3. 实习日记(一)

    2024-06-18 19:16:03       6 阅读
  4. LeetCode 746.使用最小花费爬楼梯

    2024-06-18 19:16:03       4 阅读
  5. vue.extend解决vue页面转构造函数暴露js供全局使用

    2024-06-18 19:16:03       6 阅读
  6. read code and make summer (python)

    2024-06-18 19:16:03       6 阅读
  7. XLM-RoBERTa 是一种多语言版本的 RoBERTa 模型

    2024-06-18 19:16:03       8 阅读