介绍
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)
复制代码