浏览代码

文章主题名称调整,进阶的数据响应系统开篇

HcySunYang 7 年之前
父节点
当前提交
3b66ab2665

+ 4 - 3
docs/.vuepress/config.js

@@ -36,9 +36,10 @@ module.exports = {
             '5vue-merge',
             '6vue-init-start',
             '7vue-reactive',
-            '8vue-compiler-start',
-            '9parser-intro',
-            '10vue-html-parser'
+            '8vue-reactive-dep-watch',
+            '80vue-compiler-start',
+            '90parser-intro',
+            '100vue-html-parser'
           ]
         }
       ],

+ 0 - 0
docs/art/10vue-html-parser.md → docs/art/100vue-html-parser.md


+ 1 - 1
docs/art/3vue-example.md

@@ -1,4 +1,4 @@
-# Vue 的思路之以一个例子为线索
+# 以一个例子为线索
 
 在上一节 [Vue构造函数](/note/Vue构造函数) 中,我们整理了完整的 `Vue` 构造函数,包括原型的设计和全局API的设计,并且我们专门为其整理了附录,目的是便于查看相应的方法和属性是在哪里被添加的,同时也让我们对 `Vue` 构造函数有一个大局观的认识。
 

+ 1 - 1
docs/art/4vue-normalize.md

@@ -1,4 +1,4 @@
-# Vue 的思路之选项的规范化
+# Vue 选项的规范化
 
 <p class="tip">注意:本节中当我们提到“以我们的例子为例”的时候,这里的“我们的例子”指的是《Vue的思路之以一个例子为线索》中的例子</p>
 

+ 2 - 2
docs/art/5vue-merge.md

@@ -66,7 +66,7 @@ for (key in child) {
 if (!hasOwn(parent, key))
 ```
 
-其中 `hasOwn` 函数来自于 `shared/util.js` 文件,可以 [shared/util.js 文件工具方法全解](/note/附录/shared-util) 中查看其详解,其作用是用来判断一个属性是否是对象自身的属性(不包括原型上的)。所以这个判断语句的意思是,如果 `child` 对象的键也在 `parent` 上出现,那么就不要再调用 `mergeField` 的了,因为在上一个 `for in` 循环中已经调用过了,这就避免了重复调用。
+其中 `hasOwn` 函数来自于 `shared/util.js` 文件,可以 [shared/util.js 文件工具方法全解](/note/附录/shared-util) 中查看其详解,其作用是用来判断一个属性是否是对象自身的属性(不包括原型上的)。所以这个判断语句的意思是,如果 `child` 对象的键也在 `parent` 上出现,那么就不要再调用 `mergeField` 的了,因为在上一个 `for in` 循环中已经调用过了,这就避免了重复调用。
 
 总之这两个 `for in` 循环的目的就是使用在 `parent` 或者 `child` 对象中出现的 `key(即选项的名字)` 作为参数调用 `mergeField` 函数,真正合并的操作实际在 `mergeField` 函数中。
 
@@ -824,7 +824,7 @@ function mergeHook (
 }
 ```
 
-整个函数体由三组*三目运算符*组成,有一点值得大家学习的就是这里写三目运算符的方式,是不是感觉非常的清晰异读?那么这段代码的分析我同样使用与上面代码相同的格式来写:
+整个函数体由三组*三目运算符*组成,有一点值得大家学习的就是这里写三目运算符的方式,是不是感觉非常的清晰易读?那么这段代码的分析我们同样使用与上面代码相同的格式来写:
 
 ```js
 retrun (是否有 childVal,即判断组件的选项中是否有对应名字的生命周期钩子函数)

+ 53 - 11
docs/art/7vue-reactive.md

@@ -1,4 +1,8 @@
-# Vue的初始化之数据响应系统
+# 揭开数据响应系统的面纱
+
+::: tip 注意
+本节中将频繁的使用 `依赖` 和 `观察者` 这两个词汇,它们的意义是相同的。
+:::
 
 ## 完整目录
 
@@ -2090,28 +2094,66 @@ Vue.set(data, 'someProperty', 'someVal')
 
 ### Vue.delete/$delete
 
+接下来我们继续看一下 `Vue.delete/$delete` 函数的实现,仍然是 `src/core/observer/index.js` 文件,找到 `del` 函数:
 
+```js
+export function del (target: Array<any> | Object, key: any) {
+  // 省略...
+}
+```
 
+`del` 函数接收两个参数,分别是将要被删除属性的目标对象 `target` 以及要删除属性的键名 `key`,与 `set` 函数相同,在函数体的开头是如下 `if` 语句块:
 
+```js
+if (process.env.NODE_ENV !== 'production' &&
+  (isUndef(target) || isPrimitive(target))
+) {
+  warn(`Cannot delete reactive property on undefined, null, or primitive value: ${(target: any)}`)
+}
+```
 
+检测 `target` 是否是 `undefined` 或 `null` 或者是原始类型值,如果是的话那么在非生产环境下会打印警告信息。
 
+接着是如下这段 `if` 语句块:
 
+```js
+if (Array.isArray(target) && isValidArrayIndex(key)) {
+  target.splice(key, 1)
+  return
+}
+```
 
+很显然,如果我们使用 `Vue.delete/$delete` 去删除一个数组的索引时,如上这段代码将被执行,当然了前提是参数 `key` 需要是一个有效的数组索引。与为数组添加元素类似,移除数组元素同样使用了数组的 `splice` 方法,大家知道这样是能够触发响应的。
 
+再往下是如下这段 `if` 语句块:
 
+```js
+const ob = (target: any).__ob__
+if (target._isVue || (ob && ob.vmCount)) {
+  process.env.NODE_ENV !== 'production' && warn(
+    'Avoid deleting properties on a Vue instance or its root $data ' +
+    '- just set it to null.'
+  )
+  return
+}
+```
 
+与不能使用 `Vue.set/$set` 函数一样为根数据或 `Vue` 实例对象添加属性一样,同样不能使用 `Vue.delete/$delete` 删除 `Vue` 实例对象或根数据的属性。不允许删除 `Vue` 实例对象的属性的,是出于安全因素的考虑。而不允许删除根数据对象的属性,是因为这样做也是触发不了响应的,关于触发不了响应的原因,我们在讲解 `Vue.set/$set` 时已经分析过了。
 
+接下来是 `Vue.delete/$delete` 函数的最后一段代码,如下:
 
+```js
+if (!hasOwn(target, key)) {
+  return
+}
+delete target[key]
+if (!ob) {
+  return
+}
+ob.dep.notify()
+```
 
+首先使用 `hasOwn` 函数检测 `key` 是否是 `target` 对象自身拥有的属性,如果不是那么直接返回(`return`)。很好理解,如果你将要删除的属性原本就不在该对象上,那么自然什么都不需要做。
 
-
-
-
-
-
-
-
-
-
-
+如果 `key` 存在于 `target` 对象上,那么代码将继续运行,此时将使用 `delete` 语句从 `target` 上删除属性 `key`。最后判断 `ob` 对象是否存在,如果不存在说明 `target` 对象原本就不是响应的,所以直接返回(`return`)即可。如果 `ob` 对象存在,说明 `target` 对象是响应的,需要触发响应才行,即执行 `ob.dep.notify()`。
 

+ 0 - 0
docs/art/8vue-compiler-start.md → docs/art/80vue-compiler-start.md


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

@@ -0,0 +1,6 @@
+# 进阶的数据响应系统
+
+实际上在 [揭开数据响应系统的面纱](/art/7vue-reactive.html) 一节中我们仅仅学习了数据响应系统的部分内容,比如当时我们做了一个合理的假设,即:`dep.depend()` 这句代码的执行就代表观察者被收集了,而 `dep.notify()` 的执行则代表触发了响应,但是我们并没有详细讲解 `dep` 本身是什么东西,我们只是把它当做了一个收集依赖的“筐”。除此之外我们也没有讲解数据响应系统中另一个很重要的部分,即 `Watcher` ,我们知道正是由于 `Watcher` 对所观察字段的求值才触发了字段的 `get`,从而才有了收集到该观察者的机会。本节我们的目标就是深入 `Vue` 中有关于这部分的具体源码,看一看这里面的秘密。
+
+为了更好的讲解 `Dep` 和 `Watcher`,我们需要选择一个合适的切入点,这个切入点就是 `Vue.prototype._init` 函数。为什么是 `Vue.prototype._init` 呢?因为数据响应系统的切入点是 `initState` 函数,而 `initState` 函数的调用就在 `_init` 函数中。现在我们把视线重新转移到 `_init` 函数,然后**试图从 `渲染(render)` -> `重新渲染(re-render)` 的过程探索数据响应系统更深层次的内容**。
+

+ 0 - 0
docs/art/9parser-intro.md → docs/art/90parser-intro.md