/src/core/observer/index.js
将一个正常的object转换为每个层级的属性都是响应式(可以被侦测的)的object;
// Observe.js
import defineReactive from './defineReactive.js
import arrayMethods from './rewriteArray.js'
class Observer{
constructor(value){
def(value,'__ob__',this,flase). //给value对象绑定ob属性,且不可枚举
if(Array.isArray(value)){. //数组对象的处理
value.__proto__ = arrayMethods; //修改数组的隐式原型对象为更改后的数组原型对象
}else{
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
defineReactive(value, key);
}
}
}
observeArray(value) {
for (let i = 0, l = value.length; i < l; i++) {
observe(value[i], false);
}
}
}
var obj={
a:{
m:{
n:5
}
},
b:[1,2,3]
}
observe方法是最外层级的,上来先看observe(obj). —>>> obj身上有没有 __obj__ —>>> new Observer() ---->>> 遍历下一层属性,逐个defineReactive
/src/core/observer/index.js
//defineReactive.js文件
import observe from './observe.js
export default function defineReactive(data,key,val){
if(arguments.length===2){
val=data[key]
}
//递归调用子元素,至此形成了递归,这个递归不是函数自己调用自己,而是多个函数,类循环调用;
let childOb = observe(val) //返回val的ob对象
Object.defineProperty(data,key,{
//可枚举
enumrable:true,
//可被配置,比如可以被删除delete
configurable:true,
//getter
get(){
console.log('你试图访问obj的'+key+ '属性')
return val
},
set(newValue){
console.log('你试图改变obj的'+key+'属性‘,newValue)
if(val===newValue){ return }
val=newValue
//当设置了新值,这个新值也要被observer
childOb=observe(newValue)
}
}
}
//index.js
import defineReactive from './defineReactive'
// 创建observe函数,注意函数的名字没有r,value其实是obj[key]
function observe(value){
if(typeof value != 'object') return;
//定义ob
var ob;
if(typeof value.__ob__ !== 'undefined'){
ob = value.__ob__;
}else {
ob = new Observer(value)
}
return ob
}
在这里插入图片描述
1.obj对象会先通过observe处理,看obj身上有没有__ob__属性;
2.没有则在Observe构造器中给obj对象添加__ob__属性; (精:def (obj,__ob__属性,this),这里的this指向的是实例化出来的observe对象,然后赋值给__ob__属性)
3.添加__ob__属性需要调用一个def方法:原因:__ob__属性不可枚举,所以单独使用一个def方法;
4.在Obsever类的构造器中遍历obj每一个属性,调用definReactive方法,进行数据劫持;
5.在遍历中如果该obj[key]是一个object对象,
src/core/observer/array.js
// rewriteArray.js
//得到Array
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto); //将数组的原型对象绑定在一个对象的原型上
//对数组的7个方法进行改造
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
//重写方法
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method];
// mutator是给数组方法重新定义的一个方法 def(obj,key,value)
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args); //this是当前调用数组方法的对象,args是传进来的参数
const ob = this.__ob__;
let inserted; // 给数组对象添加的元素
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.slice(2);
break;
}
if (inserted)
//给添加的所有元素绑定响应式
ob.observeArray(inserted);
return result;
});
});
export arrayMethods
/src/core/util/lang.js
export function def(obj: Object,key: string, val: any, enumerable?: boolean){
Object.definepProperty(obj,key,{
value: val,
enumerable: !!enumberable,
writable: true,
configurable: true,
}
}
/src/core/observer/index.js
/**
*设置 target._proto_的原型对象为src
*比如数组对象,arr.__proto__arrayMethods
*/
function protoAugment(target,src: Object){
target.__proto__ = src
}
/src/core/observer/index.js
/**
*在目标对象上定义指定属性
*比如数组:为数组对象定义那七个方法
*/
function copyAugment(target: Object, src:Object, keys: Array<string>){
for(let i=0; i=keys.length; i<l; i++){
const key = keys[i]
def(target, key, src[key])
}
}
/src/core/observer/dep.js
import type Watcher from './watcher'
import {remove} from '../util/index'
import {config} from '../config'
let uid=0
/**
*一个dep对应一个obj.key
*在读取响应式数据时,负责收集依赖,每个dep(或者说obj.key)依赖的watcher有哪些
*在响应式数据更新时,负责通知dep中哪些watcher去执行update方法
*/
export default class Dep {
static target: ?Watcher;
id: number;
subs: Array<Watcher>
}
construcotr(){
this.id=uid++
this.subs=[]
}
//在dep中添加watcher
addSub(sub: Watcher){
this.subs.push(sub)
}
removeSub(sub:Watcher){
remove(this.subs,sub}
}
//向watcher中添加dep
depend(){
if(Dep.target){
Dep.target.addDep(this)
}
}
/**
*通知dep中所有watcher,执行watcher.update()方法
*/
notify(){
const subs = this.subs.slice()
if(process.env.NODE_ENV !== 'production' && !config.async){
subs.sort((a,b)=> a.id - b.id);
}
for(let i=0, l=subs.length;i<l;i++){
subs[i].update()
}
}
/**
*当前正在执行的watcher,同一时间只会有一个watcher执行
*Dep.target = 当前正在执行的watcher
*通过调用pushTarget方法完成赋值,调用popTarget方法完成重置(null)
*/
Dep.target = null
const targetStack = []
//在需要进行依赖收集的时候调用,设置Dep.target=watcher
export function pushTarget (target: ?Watcher){
targetStack.push(target)
Dep.target = target
}
//依赖收集结束调用,设置Dep.target = null
export function popTarget(){
targetStack.pop()
Dep.target = targetStack[targetStack.length-1]
}
/src/core/observer/watcher.js
/**
* 一个组件一个watcher(渲染watcher)或者一个表达式watcher(用户watcher)
* 当数据更新时watcher会被触发,访问this.computedProperty时也会触发watcher
*/
export function class Watcher {
vm: Component;
expression: string;
cb: Function;
id: number;
deep: boolean;
user: boolean;
lazy: boolean;
sync: boolean;
dirty: boolean;
acive: boolean;
deps: Array<Dep>;
newDeps: Array<Dep>;
depIds: SimpleSet;
newDepIds: SimpleSet;
before: ?Function;
getter: Function;
value: any;
constructor(
vm: Component,
exOrFn: string | Function,
cb: Function,
options? : ?Object,
isRenderWatcher? : boolean
){
this.vm = vm
if(isRenderWatcher){
vm._watcher = this
}
vm._watchers.push(this)
if(options){
this.deep = !!options.deep
this.user = !!options.user
this.lazy = !!options.lazy
this.sync = !!options.sync
this.before = options.before
}else{
this.deep = this.user = this.lazy = this.sync =false
}
this.cb = cb
this.id = ++uid
this.active = true
this.dirty = this.lazy
this.deps = []
this.newDeps = []
this.depIds = new Set()
this.newDepIds = new Set()
this.expression = process.env.NODE_ENV !== 'production'
? expOrFn,toString()
: ''
if(typeof expOrFn === 'function'){
this.getter = expOrfn
}else {
// this.getter = function(){ return this.xx}
//在this.get中执行this.getter 时会触发依赖收集
//待后续this.xx 更新时就会触发响应式
this.getter = parsePath(exOrfn)
if(!this.getter){
this.getter = noop
process.env.NODE_ENV !== 'production' && warn$2("Failed watching path: \"".concat(expOrFn, "\" ") +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.', vm);
}
}
this.value = this.lazy
? undefined
: this.get()
}
/**
* 执行this.getter,并重新收集依赖
* this.getter 是实例化watcher时传递的第二个参数,一个函数或者字符串,比如updateComponent或者parsePath返回的读取this.xx属性值的函数
* 为什么要重新收集依赖?
* 因为触发更新说明有响应式数据被更新了,但是被更新的数据虽然已经经过observe观察了,但是却没有进行依赖收集,
* 所以,在更新页面时,会重新执行一次render函数,执行期间会触发读取操作,这时候进行依赖收集
*/
get() {
//打开Dep.target, Dep.target = this
pushTarget(this)
//value为回掉函数执行的结果
let value
const vm = this.vm
try{
//执行回掉函数,比如updateComponent ,进入patch阶段
value = this.getter.call(vm,vm)
}catch(e){
if(this.user){
handleError(e,vm,`getter for watcher "${this.expression}"`}
}else {
throw e
}
}finally{
if(this.deep){
traverse(value)
}
//关闭Dep.target, Dep.target=null
popTarget()
this.cleanupDeps()
}
return value
}
/**
* Add a dependency to this directive
* 1.添加dep给自己(watcher)
* 2.添加自己(watcher)到dep
*/
addDep(dep: Dep){
//判重,如果dep已经存在则不重复添加
const id = dep.id
if(!this.newDepIds.has(id){
//缓存dep.id,用于判重
this.newDepIds.add(id)
//添加
this.newDeps.push(dep)
// 避免在dep中重复添加watcher,this.depIds 的设置在cleanDeps 方法中
if(!this.depIds.has(id){
//添加watcher自己到dep
dep.addSub(this)
}
}
}
/**
* Clean up for dependency collection
*/
cleanupDeps (){
let i = this.deps.length;
while(i--){
const dep = this.deps[i]
if(!this.newDepsIds.has(dep.id)){
dep.removeSub(this)
}
}
let tmp = this.depIds
this.depIds = this.newDepIds
this.newDepIds = tmp
this.newDepIds.clear()
tmp = this.deps
this.deps = this.newDeps
this.newDeps = tmp
this.newDeps.length = {}
}
/**
*根据watcher配置项,决定接下来怎么走,一般是queueWatcher
*/
update(){
if(this.lazy){
//懒执行走这里,比如computed
//将dirty 置为true,可以让computedGetter执行重新计算computed回掉函数的执行结果
this.dirty = true
}else if(this.sync){
//同步执行,在使用vm.$watch或者watch选项时可以传一个sync选项
//当为true时在数据更新时该watcher就不走异步更新队列,直接执行this.run
//方法进行更新
//这个属性在官方文档中没有出现
this.run()
}else{
//更新时一般走这里,将watcher放入wacher队列
queueWatcher(this)
}
}
/**
* 由刷新队列函数flushSchedulerQueue调用,完成以下几件事:
* 1.执行实例化watcher传递的第二个参数,updateComponent或者获取this.xx的的一个函数(parsePath 返回的函数)
* 2.更新旧值为新值
* 3.执行实例化watcher时传递的第三个参数,比如用户watcher的回掉函数
*/
run(){
if(this.active){
//调用this.get方法
const value = this.get()
if(
value !== this.value ||
isObject(value) ||
this.deep
){
// 更新旧值为新值
const oldValue = this.value
this.value = value
if(this.user){
//如果是用户watcher,则执行用户传递的第三个参数 ---回掉函数,参数为val和oldVal
try{
this.cb.call(this.vm,value,oldValue)
}catch(e){
handleError(e,this.vm,`callback for watcher "${this.expression}")
}
}else{
//渲染watcher,this.cb=noop,一个空函数
this.cb.call(this.vm,value,oldValue)
}
}
}
}
/**
* 懒执行watcher 会调用该方法
* 比如:computed,在获取vm.computedProperty 的值时会调用该方法
* 然后执行this.get,即watcher的回调函数,得到返回值
* this.dirty被置为fales,作用是页面在本次渲染只会一次执行computed.key的回掉函数,
* 这也就是大家常说的computed和methods区别之一就是computed有缓存的原理所在
* 而页面更新后会this.dirty会重新置为true,这一步是在this.update方法中完成的
*/
evaluate(){
this.value = this.get()
this.dirty = false
}
/**
* Depend on all deps collected by this watcher
*/
depend(){
let i = this.deps.length;
while(i--){
this.deps[i].depend()
}
}
/**
* Remove self form all dependencies subscriber list
*/
teardown(){
if(this.active){
// remove self from vm's watcher list
// this is a somewhat expensive operation so we skip it
// if the vm is being destroyed
if(!this.vm._isBeingDestoryed){
remove(this.vm._watcher,this)
}
let i = this.deps.length
while(i--){
this.deps[i].removeSub(this)
}
this.active = false
}
}
}
使用场景:
区别: