使用原生 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 )

原文地址

posted @ 2017-08-02 13:59  gw_iron  阅读(485)  评论(0编辑  收藏  举报