从vue中学习defineProperty

介绍

js语言总是有些璀璨的珍珠,等待人们去挖掘,比如defineProperty, 这里主要介绍他的getter和setter,在vue中使用的比较多,这个方法很神奇,赋予了数据"劫持"的功能,那么同样ES6中的Proxy也是赋予数据"劫持"的功能,所以vue3.0想用Proxy来进一步升级vue...感觉带"劫持"功能的都很牛x的感觉...axios?...router guards...我劫..我劫..我打劫...

emmmmm....这里也不写太多了,就了解并使用一下defineProperty吧

示例

例1. 一个proxy函数

const noop = function() {}

const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop
}

// 定义一个proxy函数
function proxy (target, sourceKey, key) {
  sharedPropertyDefinition.get = function proxyGetter() {
    return this[sourceKey][key]
  }
  sharedPropertyDefinition.set = function proxySetter(val) {
    this[sourceKey][key] = val
  }
  Object.defineProperty(target, key, sharedPropertyDefinition)
}

let obj = {
  info: {
    age: 20
  }
}
// 调用proxy函数
proxy(obj, 'info', 'age')

// 这样可以通过obj.age来访问obj.info.age属性了
// 20
console.log(obj.age)

// 再来尝试使用obj.age来修改obj.info.age
obj.age = 30
// { age: 30, info: { age: 30 } }
console.log(obj)
复制代码

例2. 了解一下 -- 同一属性多个defineProperty会实行覆盖
即此例并不会输出set1, get1

let obj = {
  age: 20
}

Object.defineProperty(obj, 'age', {
  get() {
    console.log('get1')
  },
  
  set() {
    console.log('set1')
  }
})

Object.defineProperty(obj, 'age', {
  get() {
    console.log('get2')
  },
    
  set() {
    console.log('set2')
  }
})

// 输出set2
obj.age = 30
// 输出get2
console.log(obj.age)
复制代码

例3. 了解一下 -- 对象子属性修改并不会触发上一层属性的setter

let stu = {
  info: {
    name: 'jinyong',
    age: 20
  }
}

let info = stu['info']
let name = info.name

Object.defineProperty(stu, 'info', {
  get() {
    console.log('get1')
    return info
  },
    
  set(newVal) {
    console.log('set1')
    info = newVal
  }
})

Object.defineProperty(info, 'name', {
  get() {
    console.log('get2')
    return name
  },
    
  set(newVal) {
    console.log('set2') 
    name = newVal
  }
})

//  输出 get1  及 输出 set2,但并不会输出set1
stu.info.name = 'jinyong100'
复制代码

看例4前了解下以下情况,这样操作不会修改stu.info的,不解释了

let stu = {
  info: {
    name: 'jinyong',
    age: 80
  }
}
  
function test123(info) {
  info = {
    name: 'jinyong',
    age: 30
  }
}
test123(stu.info)
复制代码

例4. 结合proxy以及为对象子属性设置access property(即getter, setter)

执行vm.info.name = 'jinyong100'时会输出get1, get2, set3
执行console.log(vm.info.name)时会输出get1, get2, get3, jinyong100
应该能理解输出的结果吧。


let vm = {
  _data: {
    info: {
      name: 'jinyong'
    }
  }
}

// 相当于proxy(vm, '_data', 'info')
Object.defineProperty(vm, 'info', {
  get() {
    console.log('get1')
    return this['_data']['info']
  },

  set(newVal) {
    console.log('set1')
    this['_data']['info'] = newVal
  }
})

let info = vm._data.info
// 由于例2中的情况,虽然我们使用vm.info成功代理vm._data.info了
// 我们还是要defineProperty vm._data对象而不是vm对象
Object.defineProperty(vm._data, 'info', {
  get() {
    console.log('get2')
    return info
  },

  set(newVal) {
    console.log('set2')
    info = newVal
  }
})

// 由于例3中的情况,如果值也是一个对象,那么对其每个属性也要defineProperty
let name = info.name
Object.defineProperty(info, 'name', {
  get() {
    console.log('get3')
    return name
  },

  set(newVal) {
    console.log('set3')
    name = newVal
  }
})

vm.info.name = 'jinyong100'

console.log(vm.info.name)
复制代码

参考

面试官: 实现双向绑定Proxy比defineproperty优劣如何?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值