Comments (7)
同楼上的问题;
还有个问题:
“之所以在深度观测之前不取值是因为属性原本的 getter 由用户定义,用户可能在 getter 中做任何意想不到的事情,这么做是出于避免引发不可预见行为的考虑。"
这句话中既然指出不进行深度观测的原因是因为用户可能在getter中做任何意想不到的事情,这个事情指的是什么;既然有这个顾虑,那为什么有setter函数的时候还会进行深度观测呢? 这个时候就不用顾忌用户的任意行为吗?
from vue-design.
因为用户可能在getter中做任何意想不到的事情
比如 getter 中发送请求, 此时这个请求应当在你主动访问的时候才会触发, 如果 vue 在定义响应式数据时替你触发了 getter, 这显然是不符合你预期的, 因为你并没有主动去触发.
既然有这个顾虑,那为什么有setter函数的时候还会进行深度观测呢?
这时候不是不用顾虑, 而是放弃顾虑. 我们来看看始终保证不触发 getter 会产生什么问题.
初始:
// 检测到 getter, 不去触发它, 所以 val 没有值
if (!getter && arguments.length === 2) {
val = obj[key]
}
// 由于 val 没有值, 此处 observe(val) 没有任何作用, 所以初始时 val 不具备响应性
let childOb = !shallow && observe(val)
后续的赋值操作触发 setter
set: function reactiveSetter (newVal) {
// ...省略
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
// newVal 被观测, 具备响应性, 与初始时不一致
childOb = !shallow && observe(newVal)
dep.notify()
}
在属性自带 setter 的情况下, 如果初始时不去触发 getter 获取值进行深度观测, 就会造成再次赋值时, 新的值被观测. 此时会产生初次和后续数据响应的不一致. 当 getter 和 setter 同时存在时, 触发副作用和一致性有冲突, 当前的方案选择了保证一致性.
from vue-design.
@liximomo 非常感谢回答!
在属性自带 setter 的情况下, 如果初始时不去触发 getter 获取值进行深度观测, 就会造成再次赋值时, 新的值被观测. 此时会产生初次和后续数据响应的不一致. 当 getter 和 setter 同时存在时, 触发副作用和一致性有冲突, 当前的方案选择了保证一致性.
追问下哈:上边可能提问的不是很清楚
情况一共就下边四种应该是没问题的:
if (getter && !setter) {
// 初始化:不触发用户getter所以无副作用,不深度观测
// 重新赋值:进行深度观测,破坏一致性
}
if (getter && setter) {
// 初始化:触发用户getter有副作用,深度观测
// 重新赋值:进行深度观测,保证一致性
}
if (!getter && setter) {
// 初始化:无用户getter无副作用,深度观测
// 重新赋值:进行深度观测,保证一致性
}
if (!getter && !setter) {
// 初始化:无用户getter无副作用,深度观测
// 重新赋值:进行深度观测,保证一致性
}
-
后边三种都为了保证了一致性,触发用户getter,导致副作用( vue 在定义响应式数据时替你触发了 getter);
-
第一种情况为了保证无副作用,破坏了一致性(初始化时不深度观测,重新赋值时却深度观测);
为什么第一种情况很特殊呢?
from vue-design.
第一种仅存在 getter 的情况不存在你说的不一致, 我们仔细看下源码.
重新赋值时却时会对新的值进行深度观测, 这个逻辑是没错的:
set: function reactiveSetter (newVal) {
// 略
if (setter) {
setter.call(obj, newVal)
} else {
// 没有 setter, 所以值被赋值给了 val,
val = newVal
}
// val 被深度观测了
childOb = !shallow && observe(newVal)
dep.notify()
}
但是我们看一下 get:
get: function reactiveGetter () {
// 由于存在 getter, 所以 value 的值总是从 getter 中获得, 和 val 没有关系.
const value = getter ? getter.call(obj) : val
// 略
return value
}
看到了吗, 新值是会被深度观测, 但由于有自定义的 getter 存在, 所以 get 获取的值总是初始的值, 随变你 val 怎么变, 都和我无关.
还有你的最后两种情况由于 getter 不存在, 所以不存在触发副作用的担忧.
from vue-design.
@liximomo 感谢回答!!!
from vue-design.
虽然作者已关闭了这个issue,但是我觉得这块还是有点绕,再补充一段代码辅助说明下。
const data = {}
const value = {getterProp: {a: 1}}
Object.defineProperty(data, 'getterProp', {
enumerable: true,
configurable: true,
get: () => {
return value.getterProp;
},
set: (newValue) => {
value.getterProp = newValue;
},
})
const ins = new Vue({
data,
watch: {
'getterProp.a': () => {
console.log('触发watch绑定的依赖')
}
}
})
// 如果采用以前的方案,即不对是否有setter进行判断,如下
if (!getter && arguments.length === 2) {
val = obj[key]
}
// 执行
ins.getterProp.a = 2;
// 此时是不会触发watch的。重新赋值后。
// 接下来给属性重新赋值
ins.getterProp = {
a: 1,
}
// 然后改变属性的值
ins.getterProp.a = 2; // 此时又会触发watch。所以说响应数据的行为是不一致的
// 为了解决这个问题,采用了现在的方案,即对setter进行判断,如下
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
// 执行
ins.getterProp.a = 2; // 此时会触发watch。重新赋值后。
// 接下来给属性重新赋值(注意,此时也会触发watch,因为属性a的值变了,可忽略这次触发,不是重点关注)
ins.getterProp = {
a: 1,
}
// 然后改变属性的值
ins.getterProp.a = 2;
// 此时仍然会触发watch。响应数据的行为是一致的
from vue-design.
看来看去当既有getter也有setter的时候会有影响,那为什么不把
let childOb = !shallow && observe(val)
放入
get: function reactiveGetter () { const value = getter ? getter.call(obj) : val; childOb = !shallow && observe(value);
请有知道的帮忙解释下,谢谢了
from vue-design.
Related Issues (20)
- 域名过期了 HOT 1
- 大佬,我想为这个仓库搭建网站
- 请问编译器的章节在哪里 HOT 1
- 求解最长递增子序列的算法是不是错了?
- inject 选项的初始化及实现,有一段描述不准确
- Vue构造函数章节有张图片404了
- 大佬 你网站被劫持了 HOT 1
- 博客图片无法访问 HOT 1
- 想请问作者大大,我这边能fork一份部署到vercel,供自己学习之用吗? HOT 1
- 图片无法访问
- vue设计与实现书中错误 HOT 1
- 《Vue.js设计与实现》第4章 响应系统的作用与实现 4.5小节 嵌套的effect与effect栈 HOT 2
- 《Vue.js设计与实现》第四章 响应系统的作用与实现 4.5嵌套的effect与effect栈
- 错别字
- 《Vue.js设计与实现》5.4 合理的触发响应
- 《Vue.js设计与实现》5.8.3 避免污染原始数据 HOT 1
- 10.1 小节,双端比较的原理是不是有笔误?
- 5.1节中理解Proxy和Reflect,Reflect.get的第三个参数 HOT 2
- 13.2.4 重试机制,这里应该时候有笔误 HOT 1
- 《Vue.js设计与实现》问题记录 HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vue-design.