使用原生 js 模拟被废弃的 Object.observe()

写了两个版本,分别是使用 js 里的 Proxy (代理)和 Object.defineProperty 实现

两个版本都有各自的缺陷,大家可以按需自己选择自己需要的

  • Proxy 不能监听源对象,只能监控代理对象
  • Object.defineProperty 有新增属性的时候,无法做到自动监听

Proxy

/**
 * 使用 Proxy 来说实现被废弃的 Object.observe()
 * 
 * @param {any} target 
 * @param {any} fnBind 
 * @returns 
 */
var bind = function ( target, fnBind ) {
    bind.targets = bind.targets || []
    var targets = bind.targets
    ,   index = targets.indexOf( target )

    bind.fnBinds = bind.fnBinds || []
    var fnBinds = bind.fnBinds
    if( index == -1 ) {
        index = targets.length
        targets.push( target )
        fnBinds.push( [] )
    }
    var targetFnBinds = fnBinds[index]
    targetFnBinds.push( fnBind )

  bind.proxy = bind.proxy || new Proxy( target, {
    set: function ( target, prop, value ) {
            target[prop] = value
      for( var i = 0; i < targetFnBinds.length; i ++ ) {
        targetFnBinds[i].call( target )
      }
    }
  } )
  return bind.proxy
}

var person = {
  name: '12'
  ,age: '23'
}
var child = bind( person, function () {
  console.log( 'bind: ', this.name )
} )
person.name = 333
child.name = 444
console.log( person )
console.log( child )

Object.defineProperty

/**
 * 使用 es5 的 Object.defineProperty 特性 来实现 Object.observe()
 * 
 * @param {any} target 
 * @param {any} fnBind 
 * @returns 
 */
var bind = function ( target, fnBind ) {
    bind.targets = bind.targets || []
    bind.cloneTargets = bind.cloneTargets || []
    var targets = bind.targets
    , closeTargets = bind.cloneTargets
    ,   index = targets.indexOf( target )

    bind.fnBinds = bind.fnBinds || []
    var fnBinds = bind.fnBinds
    if( index == -1 ) {
        index = targets.length
        targets.push( target )
        closeTargets.push( Object.assign( {}, target ) )
        fnBinds.push( [] )
    }
    var targetFnBinds = fnBinds[index]
    targetFnBinds.push( fnBind )

    for( var prop in target ) {
        Object.defineProperty( target, prop, {
            set: function ( val ) {
                closeTargets[index][prop] = val
                for( var i = 0; i < targetFnBinds.length; i ++ ) {
                    targetFnBinds[i].call( target )
                }
            },
            get: function () {
                return closeTargets[index][prop]
            }
        } )
    }

  return target
}

var person = {
  name: '12'
  ,age: '23'
}
var child = bind( person, function () {
  console.log( 'bind: ', this.name )
} )
person.name = 333
child.name = 444
child.name = 555
console.log( person )
console.log( child )

你可能感兴趣的:(使用原生 js 模拟被废弃的 Object.observe())