深入浅出Vue.js(一) 变化侦测
变化侦测真是很难理解啊,还是需要结合书去看去学习
//dep.js
let uid = 0
export class Dep {
constructor(){
this.id = uid++
this.subs = []
}
addSub(sub){
this.subs.push(sub)
}
removeSub(sub){
const index = this.subs.indexOf(sub)
if(index > -1){
return this.subs.splice(index,1)
}
}
depend(){
if(window.target){
window.target.addDep(this)
}
}
notify(){
const subs = this.subs.slice()
for(let i = 0,len = subs.length;i < len;i++){
subs[i].update()
}
}
}
//observer.js
mport Dep from "./dep";
function observe(value){
if(!isObject(value)){
return
}
let ob
if(hasOwn(value,'__ob__') && value.__ob__ instanceof Observer){
ob = value.__ob__
}else{
ob = new Observer(value)
}
return ob
}
function def(obj,key,val,enumerable){
Object.defineProperty(obj,key,{
value:val,
enumerable:!!enumerable,
writable:true,
configurable:true
})
}
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
const baseMethods = ['push','pop','shift','unshift','splice','sort','reverse']
baseMethods.forEach(method => {
// 缓存原始方法
const original = arrayProto[method]
def(arrayMethods,method,function mutator(...args){
const result = original.apply(this,args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break;
case 'splice':
inserted = args.splice(2)
default:
break;
}
if(inserted){
ob.observeArray(inserted)
}
ob.dep.notify()
return result
})
})
function defineReactive(data,key,val){
let childOb = observe(val)
let dep = new Dep()
Object.defineProperty(data,key,{
enumerable:true,
configurable:true,
get(){
dep.depend()
if(childOb){
childOb.dep.depend()
}
return val
},
set(newVal){
if(val === newVal){
return
}
val = newVal
dep.notify()
}
})
}
export class Observer {
constructor(value){
this.value = value
this.dep = new Dep()
def(value,'__ob__',this)
if(Array.isArray(value)){
this.observeArray(value)
}else{
this.walk(value)
}
}
walk(obj){
const keys = Object.keys(obj)
for(let i = 0;i < keys.length;i++){
defineReactive(obj,keys[i],obj[keys[i]])
}
}
// 侦测Array中的每一项
observeArray(items){
for(let i = 0,len = items.length;i < len;i++){
observe(items[i])
}
}
}
//watcher.js
const reg = /[^\w.$]/
function parsePath(path){
if(reg.test(path)){
return
}
const segments = path.split('.')
return function(obj){
for(let i = 0;i < segments.length;i++){
if(!obj){
return
}
obj = obj[segments[i]]
}
return obj
}
}
const seenObjects = new Set()
function traverse(value){
_traverse(value,seenObjects)
seenObjects.clear()
}
function _traverse(val,seen){
let i,keys
const isArray = Array.isArray(val)
if((!isArray && !isObject(val)) || Object.isFrozen(val)){
return
}
if(val.__ob__){
const depId = val.__ob__.dep.id
if(seen.has(depId)){
return
}
seen.add(depId)
}
if(isArray){
i = val.length
while(i--) _traverse(val[i],seen)
}else{
keys = Object.keys(val)
i = keys.length
while(i--) _traverse(val[keys[i]],seen)
}
}
export class Watcher {
constructor(vm,expOrFn,cb,options){
this.vm = vm
if(options){
this.deep = !!options.deep
}else{
this.deep = false
}
this.deps = []
this.depIds = new Set()
if(typeof expOrFn === 'function'){
this.getter = expOrFn
}else{
this.getter = parsePath(expOrFn)
}
this.cb = cb
this.value = this.get()
}
get(){
window.target = this
let value = this.getter.call(this.vm,this.vm)
if(this.deep){
traverse(value)
}
window.target = undefined
return value
}
update(){
const oldValue = this.value
this.value = this.get()
this.cb.call(this.vm,this.value,oldValue)
}
addDep(dep){
const id = dep.id
if(!this.depIds.has(id)){
this.depIds.add(id)
this.deps.push(dep)
dep.addSub(this)
}
}
teardown(){
let len = this.deps.length
while(len--){
this.deps[i].removeSub(this)
}
}
}
以自己现在的努力程度,还没有资格和别人拼天赋

浙公网安备 33010602011771号