Skip to content
This repository has been archived by the owner on Feb 9, 2021. It is now read-only.

Object.defineProperty 和 Proxy 实现数据代理 #14

Open
lbwa opened this issue May 7, 2018 · 0 comments
Open

Object.defineProperty 和 Proxy 实现数据代理 #14

lbwa opened this issue May 7, 2018 · 0 comments
Labels
Vue.js Vue.js / Vue-router / Vue-cli / Vuex .etc

Comments

@lbwa
Copy link
Owner

lbwa commented May 7, 2018

MVVM 框架的个人见解

👉 MVVM架构模式

响应式原理以及数据双向绑定

👉 Repo: vue-reactive

  • Model 经由 ViewModelVue.js) 绑定 View;监听 View 变化以通过 ViewModel 更新 Model

数据代理实现

  • this.$data[key] === this[key] 成立。

Vue.js 现阶段使用 Object.definePropertyReflect.defineProperty 将逐步取代之) 实现数据代理。

// src/core/instance/state.js
const baseDescription = {
  enumerable: true,
  configurable: true,
  get: function () {},
  set: function () {}
}

function defineProxy (target, sourceKey, key) {
  baseDescription.get = function proxyGetter () {
    return this[sourceKey][key]
  }

  baseDescription.set = function proxySetter (value) {
    this[sourceKey][key] = value
  }
  Reflect.defineProperty(target, key, baseDescription)
}

// 简单实现数据代理
const vm = {
  data: {
    name: 'John Wick',
    num: 20
  }
}

const keys = Object.keys(vm.data)
const len = keys.length
for (let i = 0; i < len; i++) {
  defineProxy(vm, 'data', key[i]) // vm: { data: {...}, name: 'John Wick', num: 20 }
}

同时,ES2015 中新增的 Proxy 方法同样可以实现数据代理,在 Vue.js 3 中 Proxy 可能代替 Object.defineProperty

// 示例 1
const target = {
  keys: {
    name: 'I am a original object.'
  }
}

const handle = {
  get (target, key) {
    return key in target.keys? target.keys[key] : console.error(`There is no '${key}' in `, target.keys)
  }
}

// 通过 Proxy 实例来读取被代理的对象的键值
const proxy = new Proxy(target, handle)
proxy.name // 'I am a original object.'

// 示例 2
const target = {
  keys: {
    name: 'I am a original object'
  },

  // getter 函数必须在 target 的对象内设置,而非在 receiver 设置
  get name() {
    return this.keys.name
  }
}

/**
 * 1. receiver 仅起到提供 键值 的作用,不在其中设置 getter 或 setter。当遇到
 * target 内有 getter 函数时,将 receiver 提供给 target 中的 getter 函数
 */
const receiver = {
  keys: {
    name: 'I am a super object'
  }
}

Reflect.get(target, 'name', receiver) // "I am a super object"


// 示例 3
const target = {
  keys: {
    name: 'I am a original object'
  },

  // getter 函数必须在 target 的对象内设置,而非在 receiver 设置
  get name() {
    return this.name
  }
}

// receiver 仅起到提供 键值 的作用,不在其中设置 getter 或 setter
const receiver = {
  name: 'I am a super object'
}

const handle = {
  // 此处若传入第三个参数,那么第三个参数将表示当前的 proxy 实例
  get (target, key) {
    return Reflect.get(target, key, receiver) // 相当于 target.keys[key] 作用
  }
}

const proxy = new Proxy(target, handle)
proxy.name // 'I am a super object'
@lbwa lbwa added the Vue.js Vue.js / Vue-router / Vue-cli / Vuex .etc label May 7, 2018
@lbwa lbwa changed the title Object.defineProperty 和 Proxy 实现双向绑定(数据劫持和数据代理) Object.defineProperty 和 Proxy 实现数据代理 May 30, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Vue.js Vue.js / Vue-router / Vue-cli / Vuex .etc
Projects
None yet
Development

No branches or pull requests

1 participant