简易实现双向绑定(数据劫持)

Vue中 响应式数据绑定系统

Vue中双向数据绑定事项采用了数据劫持的方式,结合发布订阅模式,其中核心方法是Object.defineProperty(),通过劫持各个属性的setter和getter方法,来做到实时响应数据的目的。
复制代码

1. 认识Object.defineProperty()

该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
Object.defineProperty(obj, prop, descriptor)
obj: 需要定义的对象
prop:定义的属性名称
descriptor: 描述属性的内容
其中描述属性有很多配置项
复制代码
    Object.defineProperty(obj,"test",{
        configurable:true | false,//是否可以删除目标属性或是否可以再次修改属性的特性,默认false
        enumerable:true | false, //属性是否可以被枚举(使用for...in或Object.keys()),默认false
        value:任意类型的值,//属性对应的值,可以使任意类型的值,默认为undefined
        writable:true | false //属性的值是否可以被重写,默认false
    });
复制代码

1.1. 简单来个例子:

 let obj = {}
 let val
 Object.defineProperty(obj, 'test',{
     get(){
         console.log('取值了')
         return val
     },
     set(newVal){
         console.log('赋值了')
         val = newVal
     }
 })
 //obj.test 触发get方法,obj.test = 1触发set方法
复制代码

1.2. 稍微完善例子:

上面的例子加入对象的属性有多层,比如obj={test:{test:1}},里面的test就监听不到了
为此我们来完善一下
复制代码
 let obj = {name:'jeffywin',play:{sport:'basketball'}}
 function observer(obj){
     if(typeof obj !== 'object') return; //如果不是对象,则return
     for(let key in obj) {
         defineReactive(obj, key, obj[key]) // 对象,属性,内容
         observer(obj[key])//假如最后一层不是对象,把obj[key]递归下去
     }
 }
 
 function defineReactive(tar, por, val) {
     Object.defineProperty(tar, por,{
         get() {
             return val
         },
         set(newVal) {
             if(val === newVal) return
             val = newVal
         }
     })
 }
 observer(obj)//通过递归来拿到多层嵌套内容
复制代码

2. ES6 proxy代理器

var proxy = new Proxy(target, handler)
复制代码

通过构造函数生成proxy,target参数是要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为

2.1简单例子
let obj = {name: 'jeffywin'}
let proxy = new Proxy(obj,{
    get: function(target,key){
        console.log('取值')
        return target[key]
    },
    set: function(target,key,value){
        target[key] = value
    }
})
proxy.name 调用get方法,proxy.name = 'jordan' 调用set方法
复制代码
2.2简单例子完善(处理私有变量)
let obj = {_secretAge:18, _secretPlay:'play', version: 1.0}
let Api = new Proxy(obj,{
    get: function(target,key){
        if(key.startsWith('_')) {
            console.log('私有变量不能被访问')
            return false;
        }
        return target[key]
    },
    set: function(target,key,value) {
        if(key.startsWith('_')) {
            console.log('私有变量不能被修改')
            return false;
        }
        target[key] = value
    }
})
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值