소스 검색

modify typos

yoshino 7 년 전
부모
커밋
4c31904a16
1개의 변경된 파일17개의 추가작업 그리고 17개의 파일을 삭제
  1. 17 17
      docs/art/8vue-reactive-dep-watch.md

+ 17 - 17
docs/art/8vue-reactive-dep-watch.md

@@ -1723,7 +1723,7 @@ Vue.prototype.$watch = function (
 }
 ```
 
-`$watch` 方法允许我们观察数据对象的某个属性,当属性变化时执行回调。所以 `$watch` 方法至少接收两个参数,一个要观察的属性,以及一个回调函数。通过上面的代码我们发现,`$watch` 方法接收三个参数,除了前面介绍两个参数之后还接受第三个参数,它是一个选项参数,比如是否立即执行回调或者是否深度观测等。我们可以发现这三个参数与 `Watcher` 类的构造函数中的三个参数相匹配,如下:
+`$watch` 方法允许我们观察数据对象的某个属性,当属性变化时执行回调。所以 `$watch` 方法至少接收两个参数,一个要观察的属性,以及一个回调函数。通过上面的代码我们发现,`$watch` 方法接收三个参数,除了前面介绍的两个参数之后还接收第三个参数,它是一个选项参数,比如是否立即执行回调或者是否深度观测等。我们可以发现这三个参数与 `Watcher` 类的构造函数中的三个参数相匹配,如下:
 
 ```js {4-6}
 export default class Watcher {
@@ -1768,7 +1768,7 @@ if (options.immediate) {
 }
 ```
 
-我们知道 `immediate` 选项用来在属性或函数被侦听后立即执行回调,如上代码就是其实现原理,如果发现 `options.immediate` 选项为真,那么会执行回调函数,不过此时回调函数的参数只有新值没有旧值。同时取值的方式是通过前面创建的观察者实例对象的 `watcher.value` 属性。我们知道观察者实例对象的 `value` 属性,保存着被观察属性的值。
+我们知道 `immediate` 选项用来在属性或函数被侦听后立即执行回调,如上代码就是其实现原理,如果发现 `options.immediate` 选项为真,那么会执行回调函数,不过此时回调函数的参数只有新值没有旧值。同时取值的方式是通过前面创建的观察者实例对象的 `watcher.value` 属性。我们知道观察者实例对象的 `value` 属性,保存着被观察属性的值。
 
 最后 `$watch` 方法还有一个返回值,如下:
 
@@ -1804,7 +1804,7 @@ export default class Watcher {
 }
 ```
 
-首先检查 `this.active` 属性是否为真,如果为假则说明该观察者已经不处激活状态,什么都不需要做,如果为真则会执行 `if` 语句块内的代码,在 `if` 语句块内首先执行的这段代码:
+首先检查 `this.active` 属性是否为真,如果为假则说明该观察者已经不处激活状态,什么都不需要做,如果为真则会执行 `if` 语句块内的代码,在 `if` 语句块内首先执行的这段代码:
 
 ```js
 if (!this.vm._isBeingDestroyed) {
@@ -1812,7 +1812,7 @@ if (!this.vm._isBeingDestroyed) {
 }
 ```
 
-首先说明一点每个组件实例都有一个 `vm._isBeingDestroyed` 属性,它是一个标识,为真说明该组件实例已经被销毁了,为假说明该组件还没有被销毁,所以以上代码的意思是如果组件没有被销毁,那么将当前观察者实例从组件实例对象的 `vm._watchers` 数组中移除,我们知道 `vm._watchers` 数组中包含了该组件所有的观察者实例对象,所以将当前观察者实例对象从 `vm._watchers` 数组中移除是解除属性与观察者实例对象之间关系的第一步。由于这个参数的性能开销比较大,所以仅在组件没有被销毁的情况下才会执行此操作。
+首先说明一点每个组件实例都有一个 `vm._isBeingDestroyed` 属性,它是一个标识,为真说明该组件实例已经被销毁了,为假说明该组件还没有被销毁,所以以上代码的意思是如果组件没有被销毁,那么将当前观察者实例从组件实例对象的 `vm._watchers` 数组中移除,我们知道 `vm._watchers` 数组中包含了该组件所有的观察者实例对象,所以将当前观察者实例对象从 `vm._watchers` 数组中移除是解除属性与观察者实例对象之间关系的第一步。由于这个参数的性能开销比较大,所以仅在组件没有被销毁的情况下才会执行此操作。
 
 将观察者实例对象从 `vm._watchers` 数组中移除之后,会执行如下这段代码:
 
@@ -1995,7 +1995,7 @@ function initWatch (vm: Component, watch: Object) {
 }
 ```
 
-可以看到 `initWatch` 函数就是通过对 `watch` 选项遍历,然后通过 `createWatcher` 函数创建观察者对象的,需要注意的是上面代码中有一个判断条件,如下高亮代码所示:
+可以看到 `initWatch` 函数就是通过对 `watch` 选项遍历,然后通过 `createWatcher` 函数创建观察者对象的,需要注意的是上面代码中有一个判断条件,如下高亮代码所示:
 
 ```js {4}
 function initWatch (vm: Component, watch: Object) {
@@ -2058,7 +2058,7 @@ watch: {
 }
 ```
 
-如上高亮代码所示,数据对象 `data` 的属性 `a` 是一个对象,当实例化 `Watcher` 对象并观察属性 `a` 时,会读取属性 `a` 的值,这样的确能够触发属性 `a` 的 `get` 拦截器函数,但由于没有读取 `a.b` 属性的值所以对于 `b` 来讲是没有收集到任何观察者的。这就是我们常说的浅观察,直接修改属性 `a` 的值能够触发响应,而修改 `a.b` 的值是触发不了响应的。
+如上高亮代码所示,数据对象 `data` 的属性 `a` 是一个对象,当实例化 `Watcher` 对象并观察属性 `a` 时,会读取属性 `a` 的值,这样的确能够触发属性 `a` 的 `get` 拦截器函数,但由于没有读取 `a.b` 属性的值所以对于 `b` 来讲是没有收集到任何观察者的。这就是我们常说的浅观察,直接修改属性 `a` 的值能够触发响应,而修改 `a.b` 的值是触发不了响应的。
 
 深度观测就是用来解决这个问题的,深度观测的原理很简单,既然属性 `a.b` 中没有收集到观察者,那么我们就主动读取一下 `a.b` 的值,这样不就能够触发属性 `a.b` 的 `get` 拦截器函数从而收集到观察者了吗,其实 `Vue` 就是这么做的,只不过你需要将 `deep` 选项参数设置为 `true`,主动告诉 `Watcher` 实例对象你现在需要的是深度观测。我们找到 `Watcher` 类的 `get` 方法,如下:
 
@@ -2088,7 +2088,7 @@ get () {
 }
 ```
 
-如上高亮代码所示,我们知道 `Watcher` 类的 `get` 方法用来求值,在 `get` 方法内部通过调用 `this.getter` 函数对被观察的属性求值,并将求得的值赋值给变量 `value`,同时我们可以看到在 `finally` 语句块内,如果 `this.deep` 属性的值为真说明是深度观测,此时会将被观测属性的值 `value` 作为参数传递给 `traverse` 函数,其中 `traverse` 函数的作用就是递归读取被观察属性的所有子属性的值,这样被观察属性的所有子属性都将会收集到观察者,从而达到深度观测的目的。
+如上高亮代码所示,我们知道 `Watcher` 类的 `get` 方法用来求值,在 `get` 方法内部通过调用 `this.getter` 函数对被观察的属性求值,并将求得的值赋值给变量 `value`,同时我们可以看到在 `finally` 语句块内,如果 `this.deep` 属性的值为真说明是深度观测,此时会将被观测属性的值 `value` 作为参数传递给 `traverse` 函数,其中 `traverse` 函数的作用就是递归读取被观察属性的所有子属性的值,这样被观察属性的所有子属性都将会收集到观察者,从而达到深度观测的目的。
 
 `traverse` 函数来自 `src/core/observer/traverse.js` 文件,如下:
 
@@ -2184,7 +2184,7 @@ if (isA) {
 }
 ```
 
-这段代码将检测被观察属性的值是数组还是对象,无论是数组还是对象都会通过 `while` 循环对其进行遍历,并递归调用 `_traverse` 函数,这段代码的关键在于递归调用 `_traverse` 函数时所传递的第一个参数:`val[i]` 和 `val[keys[i]]`。这两个参数实际上是在读取子属性的值,这将触发子属性 `get` 拦截器函数,保证子属性能够收集到观察者,仅此而已。
+这段代码将检测被观察属性的值是数组还是对象,无论是数组还是对象都会通过 `while` 循环对其进行遍历,并递归调用 `_traverse` 函数,这段代码的关键在于递归调用 `_traverse` 函数时所传递的第一个参数:`val[i]` 和 `val[keys[i]]`。这两个参数实际上是在读取子属性的值,这将触发子属性 `get` 拦截器函数,保证子属性能够收集到观察者,仅此而已。
 
 现在 `_traverse` 函数的代码我们就解析完了,但大家有没有想过目前 `_traverse` 函数存在什么问题?别忘了前面我们删除了一段代码,如下:
 
@@ -2208,7 +2208,7 @@ obj1.data = obj2
 obj2.data = obj1
 ```
 
-上面代码中我们定义了两个对象,分别是 `obj1` 和 `obj2`,并且 `obj1.data` 属性引用了 `obj2`,而 `obj2.data` 属性引用了 `obj1`,这是一个典型的循环用,假如我们使用 `obj1` 或 `obj2` 这两个对象中的任意一个对象出现在 `Vue` 的响应式数据中,如果不做防循环引用的处理,将会导致死循环,如下代码:
+上面代码中我们定义了两个对象,分别是 `obj1` 和 `obj2`,并且 `obj1.data` 属性引用了 `obj2`,而 `obj2.data` 属性引用了 `obj1`,这是一个典型的循环用,假如我们使用 `obj1` 或 `obj2` 这两个对象中的任意一个对象出现在 `Vue` 的响应式数据中,如果不做防循环引用的处理,将会导致死循环,如下代码:
 
 ```js
 function _traverse (val: any, seen: SimpleSet) {
@@ -2228,7 +2228,7 @@ function _traverse (val: any, seen: SimpleSet) {
 }
 ```
 
-如果被观察属性的值 `val` 是一个循环用的对象,那么上面的代码将导致死循环,为了避免这种情况的发生,我们可以使用一个变量来存储那些已经被遍历过的对象,当再次遍历该对象时程序会发现该对象已经被遍历过了,这时会跳过遍历,从而避免死循环,如下代码所示:
+如果被观察属性的值 `val` 是一个循环用的对象,那么上面的代码将导致死循环,为了避免这种情况的发生,我们可以使用一个变量来存储那些已经被遍历过的对象,当再次遍历该对象时程序会发现该对象已经被遍历过了,这时会跳过遍历,从而避免死循环,如下代码所示:
 
 ```js {7-13}
 function _traverse (val: any, seen: SimpleSet) {
@@ -2300,7 +2300,7 @@ const watchers = vm._computedWatchers = Object.create(null)
 const isSSR = isServerRendering()
 ```
 
-其中 `watchers` 常量与组件实例的 `vm._computedWatchers` 属性拥有相同的引用,且初始值都是通过 `Object.create(null)` 创建的空对象,`isSSR` 常量用来判断是否是服务端渲染的布尔值。接着开启一个 `for` 循环,后续的所有代码都写在了这个 `for` 循环中:
+其中 `watchers` 常量与组件实例的 `vm._computedWatchers` 属性拥有相同的引用,且初始值都是通过 `Object.create(null)` 创建的空对象,`isSSR` 常量用来判断是否是服务端渲染的布尔值。接着开启一个 `for` 循环,后续的所有代码都写在了这个 `for` 循环中:
 
 ```js
 for (const key in computed) {
@@ -2386,7 +2386,7 @@ if (process.env.NODE_ENV !== 'production' && getter == null) {
 }
 ```
 
-在非生产环境下如果发现 `getter` 不存在,则直接打印警告信息,提示你计算属性没有对应的 `getter`。也就是说计算属性的函数写法实际上是对象写法的简化,如下这两写法是等价的:
+在非生产环境下如果发现 `getter` 不存在,则直接打印警告信息,提示你计算属性没有对应的 `getter`。也就是说计算属性的函数写法实际上是对象写法的简化,如下这两写法是等价的:
 
 ```js
 computed: {
@@ -2422,7 +2422,7 @@ if (!isSSR) {
 
 只有在非服务端渲染时才会执行 `if` 语句块内的代码,因为服务端渲染中计算属性的实现本质上和使用 `methods` 选项差不多。这里我们着重讲解非服务端渲染的实现,这时 `if` 语句块内的代码会被执行,可以看到在 `if` 语句块内创建了一个观察者实例对象,我们称之为**计算属性的观察者**,同时会把计算属性的观察者添加到 `watchers` 常量对象中,键值是对应计算属性的名字,注意由于 `watchers` 常量与 `vm._computedWatchers` 属性具有相同的引用,所以对 `watchers` 常量的修改相当于对 `vm._computedWatchers` 属性的修改,现在你应该知道了,`vm._computedWatchers` 对象是用来存储计算属性观察者的。
 
-另外有几点需要注意,首先创建计算属性观察者时所传递的第二个参数是 `getter` 函数,也是说计算属性观察者的求值对象是 `getter` 函数。传递的第四个参数是 `computedWatcherOptions` 常量,它是一个对象,定义在 `initComputed` 函数的上方:
+另外有几点需要注意,首先创建计算属性观察者时所传递的第二个参数是 `getter` 函数,也是说计算属性观察者的求值对象是 `getter` 函数。传递的第四个参数是 `computedWatcherOptions` 常量,它是一个对象,定义在 `initComputed` 函数的上方:
 
 ```js
 const computedWatcherOptions = { computed: true }
@@ -2444,7 +2444,7 @@ if (!(key in vm)) {
 }
 ```
 
-这段代码首先检查计算属性的名字是否已经存在于组件实例对象中,我们知道在初始化计算属性之前已经初始化了 `props`、`methods` 和 `data` 选项,并且这些选项数据都会定义在组件实例对象上,由于计算属性也需要定义在组件实例对象上,所以需要使用计算属性的名字检查组件实例对象上是否已经有了同名的定义,如果该名字已经定义在组件实例对象上,那么有可能是 `data` 数据或 `props` 数据或 `methods` 数据之一,对于 `data` 和 `props` 来讲他们是不允许被 `computed` 选项中的同名属性覆盖的,所以在非生产环境中还要检查计算属性中是否存在 `data` 和 `props` 选项同名的属性,如果有则会打印警告信息。如果没有则调用 `defineComputed` 定义计算属性。
+这段代码首先检查计算属性的名字是否已经存在于组件实例对象中,我们知道在初始化计算属性之前已经初始化了 `props`、`methods` 和 `data` 选项,并且这些选项数据都会定义在组件实例对象上,由于计算属性也需要定义在组件实例对象上,所以需要使用计算属性的名字检查组件实例对象上是否已经有了同名的定义,如果该名字已经定义在组件实例对象上,那么有可能是 `data` 数据或 `props` 数据或 `methods` 数据之一,对于 `data` 和 `props` 来讲他们是不允许被 `computed` 选项中的同名属性覆盖的,所以在非生产环境中还要检查计算属性中是否存在 `data` 和 `props` 选项同名的属性,如果有则会打印警告信息。如果没有则调用 `defineComputed` 定义计算属性。
 
 `defineComputed` 函数就定义在 `initComputed` 函数的下方,如下是 `defineComputed` 函数的签名及最后一句代码:
 
@@ -2544,7 +2544,7 @@ function createComputedGetter (key) {
 }
 ```
 
-可以看到 `createComputedGetter` 函数只是返回一个叫做 `computedGetter` 的函数,并没有做任何其他事情。也就是说计算属性真正的 `get` 拦截器函数就是 `computedGetter` 函数,如下:
+可以看到 `createComputedGetter` 函数只是返回一个叫做 `computedGetter` 的函数,并没有做任何其他事情。也就是说计算属性真正的 `get` 拦截器函数就是 `computedGetter` 函数,如下:
 
 ```js
 sharedPropertyDefinition = {
@@ -2624,7 +2624,7 @@ depend () {
 }
 ```
 
-`depend` 方法的内容很简单,检查 `this.dep` 和 `Dep.target` 是否全部有值,如果都有值的情况下便会执行 `this.dep.depend` 方法。这里我们首要知道 `this.dep` 属性是什么,实际上计算属性的观察者与其他观察者对象不同,不同之处首先会体现在创建观察者实例对象的时候,如下是 `Watcher` 类的 `constructor` 方法中的一段代码:
+`depend` 方法的内容很简单,检查 `this.dep` 和 `Dep.target` 是否全部有值,如果都有值的情况下便会执行 `this.dep.depend` 方法。这里我们首要知道 `this.dep` 属性是什么,实际上计算属性的观察者与其他观察者对象不同,不同之处首先会体现在创建观察者实例对象的时候,如下是 `Watcher` 类的 `constructor` 方法中的一段代码:
 
 ```js {9-11}
 constructor (
@@ -2688,7 +2688,7 @@ evaluate () {
 }
 ```
 
-我们知道计算属性的观察者惰性求值,所以在创建计算属性观察者时除了 `watcher.computed` 属性为 `true` 之外,`watcher.dirty` 属性的值也为 `true`,代表着当前观察者对象没有被求值,而 `evaluate` 方法的作用就是用来手动求值的。可以看到在 `evaluate` 方法内部对 `this.dirty` 属性做了真假判断,如果为真则调用观察者对象的 `this.get` 方法求值,同时将`this.dirty` 属性重置为 `false`。最后将求得的值返回:`return this.value`。
+我们知道计算属性的观察者惰性求值,所以在创建计算属性观察者时除了 `watcher.computed` 属性为 `true` 之外,`watcher.dirty` 属性的值也为 `true`,代表着当前观察者对象没有被求值,而 `evaluate` 方法的作用就是用来手动求值的。可以看到在 `evaluate` 方法内部对 `this.dirty` 属性做了真假判断,如果为真则调用观察者对象的 `this.get` 方法求值,同时将`this.dirty` 属性重置为 `false`。最后将求得的值返回:`return this.value`。
 
 这段代码的关键在于求值的这句代码,如下高亮部分所示: