目录
Reflect.get()
的了解与学习,可以直接看Reflect.get() - JavaScript | MDN。
不过说实话,我在看完之后,仍然理解得不甚透彻。
那么你呢?你对其的理解又如何呢?如果让你回答以下例子的输出,你能够得出正确的答案吗?(答案在最后)
问题1:
javascript
const obj = { bar: 1 }
const value = Reflect.get(obj, 'bar', { bar: 2 })
console.log('value', value)
问题2:
javascript
const obj = {
get bar() {
return 1
}
}
const value = Reflect.get(obj, 'bar', { bar: 2 })
console.log('value', value)
问题3:
javascript
const obj = {
get bar() {
return this.foo
},
foo:1
}
const value = Reflect.get(obj, 'bar', { bar: 2,foo:3 })
console.log('value', value)
我的困惑,其实是在阅读《Vue.js设计与实现》中提到Reflect.get
的代码时产生的。总的来说,我的困惑可以用以下的两个例子来表达:
为什么p.bar不会无限循环?
这个例子是这样的:
javascript
const obj = { bar: 1 };
const p = new Proxy(obj, {
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
}
});
console.log(p.bar)
先说说为什么我会得到p.bar
会无限循环这个错误结论:
- 读取
p.bar
会进入到getter
,此时会return Reflect.get(target, key, receiver)
- 那么这时就会用
receiver
也就是p
来替代target
来读取key
,也就是读取p.bar
,从而又回到了第一步,从而导致无限循环。
但是,实际上这个例子是可以输出1
的,并不存在无限循环,这个推导是错误的,那么实际上发生了什么呢?
以下是我理解这个例子发生的细节
obj
是目标对象target
,p
是代理对象,在代理对象的get
中,调用了Reflect.get(target, key, receiver)
,其中receiver
其实就是代理对象p
当尝试读取p.bar
时,实际上发生了以下步骤:
- 触发代理对象的
get
处理程序 - 在
get
处理程序中,调用了Reflect.get(target,key,receiver)
,receiver
就是代理对象本身 - 这时因为
target[key]
并不会触发getter
,因此此时直接返回target[key]
的值,也就是1。
至此流程就结束了,不存在循环的问题。
为什么这个p.bar又不会无限循环?
javascript
const obj = {
foo: 1,
get bar() {
return this.foo
}
}
const p = new Proxy(obj, {
get(target, key, receiver) {
return Reflect.get(target, key, receiver)
}
})
console.log(p.bar)
同样的,我先解释一下为什么我会推导出上面这个例子无限循环的错误结论:
- 访问
p.bar
,会触发getter
,执行return Reflect.get(target, key, receiver)
- 这时
target[key]
的读取会触发getter
,因此会使用receiver
替代target
,也就是会用代理对象p
来替代target
- 这时就相当于访问
p.bar
,就回到了第1步,从而导致无限循环。
正确的步骤:
- 访问
p.bar
,会触发getter
,执行return Reflect.get(target, key, receiver)
- 此时
target[key]
会访问对象的getter
,因此Relect.get
会将getter
中的this
设置为receiver
也就是代理对象p
,也就相当于return p.foo
p.foo
同样会触发代理对象get
处理程序,执行return Reflect.get(target, key, receiver)
,但是此时的target[key]
是obj.foo
,它不会访问对象的getter
,因此会直接返回1
至此整个流程就结束了。
结论
- 使用
Reflect.get(target, key, receiver)
时,如果target[key]
会访问对象的getter
时,getter
中的this
会被设置为receiver
- 使用
Reflect.get(target, key, receiver)
时,如果target[key]
不会访问对象的getter
时,那么此时会直接返回目标对象上该属性的值,也就是target[key]
最后,回到开头的问题,
问题1:
javascript
const obj = { bar: 1 }
const value = Reflect.get(obj, 'bar', { bar: 2 })
console.log('value', value) // value 1
问题2:
javascript
const obj = {
get bar() {
return 1
}
}
const value = Reflect.get(obj, 'bar', { bar: 2 })
console.log('value', value) // value 1
问题3:
javascript
const obj = {
get bar() {
return this.foo
},
foo:1
}
const value = Reflect.get(obj, 'bar', { bar: 2,foo:3 })
console.log('value', value) // value 3