machao07 / interview-questions

前端技术栈相关面试知识点( Vue、React、Typescript、JavaScript...),喜欢请点start

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proxy、Object.defineProperty()

machao07 opened this issue · comments

1、Proxy

Proxy 劫持的是整个对象

Proxy 两个参数

  • target 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理
  • handler 一个通常以函数作为属性的对象,用来定制拦截行为
const origin = {}
const obj = new Proxy(origin, {
  get: function (target, propKey, receiver) {
		return '10'
  }
});

obj.a // 10
obj.b // 10
origin.a // undefined
origin.b // undefined

handler 对象常用方法

方法 描述
handler.has() in 操作符的捕捉器
handler.get() 属性读取操作的捕捉器
handler.set() 属性设置操作的捕捉器
handler.deleteProperty() delete 操作符的捕捉器
handler.ownKeys() Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器
handler.apply() 函数调用操作的捕捉器
handler.construct() new 操作符的捕捉器

2、Object.defineProperty()

直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

defineProperty 三个参数

  • obj 要定义属性的对象
  • prop 要定义或修改的属性的名称或 Symbol
  • descriptor 要定义或修改的属性描述符
const obj = {}
Object.defineProperty(obj, "a", {
  value : 1,
  writable : false, // 是否可写 
  configurable : false, // 是否可配置
  enumerable : false // 是否可枚举
})

obj.a = 2 // 无效
delete obj.a // 无效
for(key in obj){
  console.log(key) // 无效 
}

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 // 开始获取属性 

源码

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      // ...
      if (Dep.target) {
        // 收集依赖
        dep.depend()
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      // ...
      // 通知视图更新
      dep.notify()
    }
  })

对象新增属性不更新原因

data init 是在生命周期 created 之前的操作,会对 data 绑定一个观察者 Observer,之后 data 中的字段更新都会通知依赖收集器Dep触发视图更新

在 Observer data 时,新增属性并不存在,自然就不会有 getter, setter

对比

  • Proxy 作为新标准将受到浏览器厂商重点持续的性能优化

- Proxy 能观察的类型比 defineProperty 更丰富

  • Proxy 不兼容IE,也没有 polyfill, defineProperty 能支持到IE9

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

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