「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」
众所周知,响应式就是数据发生变化,那么对应的视图随之更新,其基本实现(vue那种)就是对象的访问器属性getter和setter 。使用get和set有两种方式。
一 字面量对象
我们只要在属性前面加 set 或者 get 即可设置这个属性的访问器特性。 get 一定要return。 set 里面不要修改自己,会死循环,set的默认参数就是被赋的新值。 我们只要在
const book = {
get page(){
return 10
},
set page(val){
this.page = Number(val)
},
set log(val){
return '快去看书'
},
name: '百炼刚',
author:'unknown'
}
二使用defineProperty
defineProperty
可以设置对象的属性的特性。简单回顾一下。
访问器属性 enumberable 可遍历 keys ,for in ,点语法 configuable 可配置 是否能再次修改其特性 getter 读取时调用 setter 修改时调用
数据属性
enumberable 同访问器
configuable 同访问器
writable 可修改
value 属性的值
我们只关注get 和set ,逻辑值类型的特性不设置,默认都是false。三个参数,分别是 对象实例、属性名、特性选项。 如果你要设置 a.b.c的特性,那就应是是 传入 a.b ,c, options
Object.defineProperty(b, 'name', {
set(val) {
if(val ==='111'){
this.name = val
}
},
get(){ return 'a'}
})
如果要设置多个属性,可以遍历调用defineProperty,也可以使用它的复数形式 defineProperties(obj,{[key]: {options}})
,options和单数形式是一样的。
Object.defineProperties(b, {
key2:{
configurable: true ,
enumerable:true ,
get(){
return 4
},
set(val) {
this.key2 = Number(val)
}
},
key3: {
writable:false ,
configurable: false ,
}
})
三 proxy
Proxy
对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
new Proxy(target, handler)
, 经查mdn 发现这个新函数似乎比defineProperty更加强大吗,这里就简单列举一下,我们主要关注set 和 get。
-
handler.preventExtensions()
Object.preventExtensions
方法的捕捉器。 -
handler.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor
方法的捕捉器。 -
handler.has()
in
操作符的捕捉器。 -
handler.get()
属性读取操作的捕捉器。 -
handler.set()
属性设置操作的捕捉器。 -
handler.deleteProperty()
delete
操作符的捕捉器。 -
handler.ownKeys()
Object.getOwnPropertyNames
方法和Object.getOwnPropertySymbols
方法的捕捉器。 -
handler.apply()
函数调用操作的捕捉器。 -
handler.construct()
new
操作符的捕捉器。`
proxy的写法更为简洁。传入是一个对象和它的代理逻辑,不需要指定属性。 具体属性是直接写在捕获器的。就是要注意,严格模式下, set捕获器,必须返回一个布尔值,意思是是否设置成功,但是我们怎么知道是否设置成功,那就需要Reflect了。
proxy没有不能监控数组这个问题,对于数组,key就是索引。
下面这种写法也并不会造成死循环。因为,这就是代理。实际上,它只是拦截通过代理的操作,然后转移到目标,如果直接操作目标,实际上不会触发代理,操作代理就是通过代理操作目标。 这就跟租房可以找中介,也可以不找中介一样,经过中介,中介就有操作的余地。
new Proxy({}, {
get(target, key){
return target[key]
},
set(target,key , val){
//some code
target[key] = val
//return true
}
})
Reflect
这个Reflect 和Proxy还真是天生一对, Reflect是一个内置对象,类似Math,上面挂载了许多方法,这些方法就类似于某些操作。 其中 Refect.set() 和reflect.get(),的参数就和上面proxy的handler是一样的。 其作用就是执行,读取和修改某个属性,好像没啥用,get的返回值就是读取的属性值,set的返回值代表这个修改操作是否成功
proxy和defineProperty有一点是相同的,那就是只能捕获一层属性,如果想捕获某个引用类型的属性,同样是是再来一个proxy。操作多层的情况, 对于getter而言,要访问下面的属性,必须访问上面的属性,所以getter可以捕获到表面一层,不知道到底访问了下面具体的内容是什么,但是set就完全无感知了。
如果直接用defineproperty也是这样, 不过需要有多层的时候,用defineProperty,总觉得有些怪怪的。