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