MVVM双向绑定之Object.defineProperty

本文深入探讨了MVVM设计模式及双向绑定原理,通过ES5的Object.defineProperty实现数据响应式更新,展示了类似Vue.js中双向绑定效果的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在的前端框架主流都是用的mvvm双向绑定的设计思想,vue.js react.js angular.js都是这种思想,通过viewmodel分别去和model,view层进行双向绑定,这种思想使我们的前端框架使用起来更加方便。而这种双向绑定的思想背后的原理主要是ES5的Object.defineProperty属性。

Object.defineProperty

通过下面一段代码实例,我们来简单看下Object.defineProperty属性有哪些功能:

let obj = {a:'1'}
// 数据描述(bool值默认true)
Object.defineProperty(obj,'b',{
	value:'2',
	configuarble:  false,	// 是否可以删除属性delete 是否可以再次设置特性
	enumerable: false,	// 是否可以被枚举 for..in Object.keys() 使用
	writable: false	// 是否可以被重写 false 时obj.a不能改变值
})
obj.b = '3'
console.log(obj.b)	// 2
delete obj.b
console.log(obj.b)	// 2
console.log(Object.keys(obj))	// ["a"]

// 存储器描述
//(当使用了getter或setter方法,不允许使用writable和value属性)
Object.defineProperty(obj,'c',{
	// configuarble: true | false,	// 是否可以删除属性delete 是否可以再次设置特性
	// enumerable: true | false,	// 是否可以被枚举 for..in Object.keys() 使用
	get: function(){
	  // 当获取值的时候触发的函数
	  console.log('this get on')
	  return 'this get on1'
	},
	
	set: function(value){
	  // 当设置值的时候触发的函数
	  console.log('this set on' + value)
	}
})
obj.c 	// this get on
console.log(obj.c)	// this get on  this get on1
obj.c = 5 // this set on5
复制代码

这其中存储器属性里的get set属性就是我们mvvm核心思想里所用到的。

Object.defineProperty模拟双向绑定

我们来看看下面这一段代码

<input type="text" ><span></span>

<script>
let obj = {}
Object.defineProperty(obj, 'hello', {
  set: function(newValue) {
    document.querySelector('input').value = newValue
    document.querySelector('span').innerHTML = newValue
  }
})
document.addEventListener('keyup', function(e){
  obj.hello = e.target.value
})
</script>
复制代码

达到的效果是

在input 输入什么右边的span内容也会响应式的跟着去改变

给obj.hello赋值修改input输入框和span里面的内容也会跟着变化

这是不是很像vue.js里面的双向绑定,原理其实就这么简单!

### Vue2 中通过 `Object.defineProperty` 实现双向绑定的原理 在 Vue2 的实现中,`Object.defineProperty` 是其核心工具之一,用于完成数据劫持并实现双向绑定。以下是其实现过程的具体分析: #### 数据劫持 Vue2 需要对所有的 data 属性进行拦截操作,以便能够监听到属性的变化。这一功能由 `Object.defineProperty` 提供支持。它允许开发者自定义对象属性的行为,包括设置 getter setter 方法。 对于每一个需要监控的数据项,都会调用如下逻辑: ```javascript function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { // 当读取该属性时触发 console.log(`Getting property ${key}`); return val; }, set: function reactiveSetter(newVal) { // 当修改该属性时触发 if (newVal === val) return; console.log(`Setting property ${key} to`, newVal); val = newVal; // 更新值 // 此处会通知视图更新或其他依赖此数据的地方 } }); } ``` 上述代码展示了如何使用 `Object.defineProperty` 定义一个具有 getter setter 的响应式属性[^1]。每当这个属性被访问或者更改时,相应的回调会被执行。 #### 构建观察者模式 为了使整个系统更加灵活高效,Vue 还引入了发布/订阅机制。具体来说,每个属性都关联了一个 Dep 对象(即依赖收集器),而组件中的 watcher 则负责监视特定属性的变化,并在其变化时刷新对应的 DOM 节点。 当初始化实例的时候,Vue 会对传入的 options 参数里的 data 对象做一次深递归遍历,从而确保即使是嵌套的对象也能变成响应式的[^5]。 #### 缺陷与局限性 尽管 `Object.defineProperty` 功能强大,但也存在一些不足之处。例如无法检测新增加或删除掉的属性;另外如果目标是一个数组,则原生的方法如 push/pop 等不会触发相应事件,因此 Vue 特意重写了部分 Array 原型上的方法来弥补这一点[^4]。 综上所述,借助于 JavaScript 自身提供的 API —— `Object.defineProperty` ,再加上巧妙的设计思路,最终实现了高效的 MVVM 模式下的双向绑定效果。 ```python print("以上是对 Vue2 如何利用 Object.defineProperty 达成双向绑定的一个概括说明") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值