「前端」Vue 響應式原理

Vue 響應式原理

ES5

var data = {
  name: 'Jack Wang',
  age: 21,
  salary: 3500,
  array: ['Jack', 'should', 'fighting']
}
// 模擬渲染
function render() {
  console.log('render')
}
// 定義需要重寫的數組方法
var method = ['push', 'pop', 'unshift', 'shift', 'reverse', 'sort', 'splice']
// 獲取數組原型
var arrayProto = Array.prototype
// 創建新的原型對象
var proto = Object.create(arrayProto)
// 遍歷需要重寫的數組方法
method.forEach(function(method) {
  // 修改新的原型對象
  proto[method] = function() {
    // 調用數組原型方法
    var res = arrayProto[method].call(this, ...arguments)
    render()
    return res
  }
})
// 數據劫持/代理方法
function observe(obj) {
  // 非對象類型直接返回
  if (!obj || typeof obj !== 'object') {
    return
  }
  // 爲數組則將新的原型添加到其原型鏈上
  if (Array.isArray(obj)) {
    obj.__proto__ = proto
    return
  }
  // 遍歷對象 key 將其傳入
  Object.keys(obj).forEach(function(key) {
    defineReactive(obj, key, obj[key])
  })
}
// 設置對象屬性
function defineReactive(obj, key, value) {
  // 遞歸子屬性
  observe(value)
  Object.defineProperty(obj, key, {
    // 重寫 getter
    get: function() {
      console.log('get')
      return value
    },
    // 重寫 setter
    set: function(newValue) {
      console.log('set', newValue)
      // 遞歸子屬性
      observe(newValue)
      // 若新值不等於舊值 則發生渲染
      if (newValue !== value) {
        value = newValue
        render()
      }
    }
  })
}
// 進行數據劫持/代理
observe(data)

ES6 Proxy

var data = {
  name: 'Jack Wang',
  age: 21,
  salary: 3500,
  array: ['Jack', 'will', 'be', 'the', 'best']
}
// 模擬渲染
function render(params) {
  console.log('render')
}
// 代理邏輯
var handler = {
  get(target, key) {
    console.log('get')
    // 若獲取到的值爲對象 則遞歸
    if (typeof target[key] === 'object' && target[key] !== null) {
      return new Proxy(target[key], key)
    }
    return Reflect.get(target, key)
  },
  set(target, key, value) {
    console.log('set', value)
    // 若設置對象的 length 屬性 則直接返回
    if (key === 'length') {
      return
    }
    Reflect.set(target, key, value)
    render()
  }
}
// 數據代理
var proxy = new Proxy(data, handler)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章