vue 는 observer 와 watcher 소스 코드 분석 을 어떻게 실현 합 니까?

7817 단어 vueobserverwatcher
본문 은 당신 을 도와 무엇 을 할 수 있 습 니까?vue 양 방향 으로 연 결 된 친구 가 궁금 하면 호기심 을 일부 완화 시 킬 수 있 고$watch 를 어떻게 실현 하 는 지 알 아 볼 수 있 습 니 다.
전정 회고
나 는 이전에 건어물 이 별로 없 는 글 을 한 편 쓰 고 큰 구 덩이 를 팠 다.
오늘 은 하루 를 채 우 고 하 나 를 더 깎 으 려 고 합 니 다.
말 나 온 김 에 본문 을 보기 전에 Object.defineProperty 를 모 르 면 신기 한 것 을 해석 해 야 합 니 다Object.defineProperty.
vue 의 작가,사람 이 잘 생 겼 고 코드 도 잘 썼 다 는 것 을 감개 할 수 밖 에 없다.본 고 는 작가 의 소스 코드 에 따라 추출 한 것 이다.
본문 은 무엇 을 실현 할 것 인가
전편 에서 약속 한 바 와 같이 본 고 는$wacth 를 실현 해 야 한다.

const v = new Vue({
 data:{
 a:1,
 b:2
 }
})
v.$watch("a",()=>console.log("  ,$watch  "))
setTimeout(()=>{
 v.a = 5
},2000) //     ,$watch  
모두 가 생각 을 정리 하 는 것 을 돕 기 위해 서.우 리 는 가장 간단 한 실현 을 할 것 이다.대상 만 생각 하고 배열 은 생각 하지 않 습 니 다.
1.observer 구현
사고방식:우 리 는Object.defineProperty의 특성 을 알 았 으 니,우 리 는 그것 의 set 와 get 을 이용 할 것 이다.우 리 는 observe 의 대상 을 재 귀 를 통 해 모든 속성 을 하위 속성의 속성 을 포함 하여 set 와 get 을 추가 할 것 입 니 다.이렇게 하면 이 대상 의 특정한 속성 에 값 을 부여 하면 set 를 촉발 합 니 다.시작 합 시다.

export default class Observer{
 constructor(value) {
 this.value = value
 this.walk(value)
 }
 //  。。        observe
 walk(value){
 Object.keys(value).forEach(key=>this.convert(key,value[key]))
 }
 convert(key, val){
 defineReactive(this.value, key, val)
 }
}


export function defineReactive (obj, key, val) {
 var childOb = observe(val)
 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 get: ()=>val,
 set:newVal=> { 
 childOb = observe(newVal)//             。    ,  set/get。。
 }
 })
}


export function observe (value, vm) {
 if (!value || typeof value !== 'object') {
 return
 }
 return new Observer(value)
}

코드 는 간단 합 니 다.모든 속성(하위 속성 포함)에 get/set 를 추가 합 니 다.그러면 이 대상 의 할당 이 있 으 면 set 방법 을 촉발 합 니 다.
그래서 우 리 는 메 시 지 를 써 야 합 니까-구독 기 를 써 야 합 니까?
이렇게 되면 set 방법 을 터치 하면 우 리 는 통 지 를 보 내 고 이 메 시 지 를 구독 하면 어떻게 됩 니까?그렇지..소식 을 듣 고 반전 을 촉발 하 다.
2.메시지-구독 기
아주 간단 합 니 다.우 리 는 하나의 배열 을 유지 합 니 다.이 배열 은 구독 을 놓 고 있 습 니 다.notify 를 터치 하면 구독 자 는 자신의 update 방법 을 사용 합 니 다.

export default class Dep {
 constructor() {
 this.subs = []
 }
 addSub(sub){
 this.subs.push(sub)
 }
 notify(){
 this.subs.forEach(sub=>sub.update())
 }
}
그래서 set 함수 가 호출 될 때마다 우리 가 notify 를 터치 해 야 하 는 거 아니 야?그래서 저희 가 코드 를 완전 하 게 채 웠 어 요.

 export function defineReactive (obj, key, val) {
 var dep = new Dep()
 var childOb = observe(val)
 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 get: ()=>val,
 set:newVal=> {
  var value = val
  if (newVal === value) {
  return
  }
  val = newVal
  childOb = observe(newVal)
  dep.notify()
 }
 })
 }
그럼 문제 가 생 겼 습 니 다.구독 자 누구 야?네,Watcher 입 니 다.dep.notify()가 구독 자,즉 Watcher 를 옮 겨 다 니 며 그의 update()방법 을 호출 합 니 다.
3.하나의 Watcher 실현
우 리 는 이 Watcher 가 무엇 을 써 야 할 지 상상 했다.update 방법?
v.$watch("a",()=>console.log("하하,$watch 성공")
표현 식(바로 그"a")과 반전 함수 입 니 다.이것 은 가장 기본 적 인 것 이기 때문에 우 리 는 간단하게 씁 니 다.

export default class Watcher {
 constructor(vm, expOrFn, cb) {
 this.cb = cb
 this.vm = vm
 //    .   fuction  expression,       expression
 this.expOrFn = expOrFn
 this.value = this.get()
 }
 update(){
 this.run()
 }
 run(){
 const value = this.get()
 if(value !==this.value){
 this.value = value
 this.cb.call(this.vm)
 }
 }
 get(){
 //    。。   fuction  expression
 const value = this.vm._data[this.expOrFn]
 return value
 }
}
그러면 문제 가 생 겼 습 니 다.우 리 는 어떻게 addSub()를 통 해 Watcher 를 넣 을 것 입 니까?
우 리 는 var dep=new Dep()가 폐쇄 되 어 있 는 것 을 발견 했다.우 리 는 Watcher 의 구조 함수 에서 this.get 을 호출 하 는 것 을 발견 했다.그래서 우 리 는 위 에서 손발 을 움 직 여 Object.defineProperty 의 get 이 호출 할 함 수 를 수정 하여 Watcher 의 구조 편지 수 호출 인지 아 닌 지 를 판단 할 수 있다.만약 에 그 가 바로 이 속성의 구독 자 라 는 것 을 설명 하고 과감하게 그 를 addSub()에 넣 을 수 있다.그 문제 가 왔 습 니까?
나 는 그 가 Watcher 의 this.get 호출 이 라 고 어떻게 판단 합 니까?우리 가 일반적으로 호출 한 것 이 아 닙 니 다.
네,Dep 에서 전체 국면 에서 유일한 변 수 를 정의 하고 생각 에 따라 쓰 겠 습 니 다.

export default class Watcher {
 ....       ....
 get(){
 Dep.target = this
 //    。。   fuction  expression
 const value = this.vm._data[this.expOrFn]
 Dep.target = null
 return value
 }
}
이렇게 되면 우 리 는 Object.defineProperty 의 get 호출 함수 에서 값 이 있 는 지 없 는 지 판단 하면 Watcher 가 get 에 있 는 지,아니면 우리 가 직접 할당 을 보고 있 는 지 알 수 있 습 니 다.Watcher 라면 addSub(),코드 를 보충 합 니 다.

export function defineReactive (obj, key, val) {
 var dep = new Dep()
 var childOb = observe(val)

 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 get: ()=>{
 //     watch    
 if(Dep.target){
 dep.addSub(Dep.target)
 }
 return val
 },
 set:newVal=> {
 var value = val
 if (newVal === value) {
 return
 }
 val = newVal
 childOb = observe(newVal)
 dep.notify()
 }
 })
}

마지막 으로 잊 지 마 세 요.Dep.js 에 이 한 마디 를 더 해 주세요.
Dep.target = null
4.하나의 Vue 구현
한 걸음 만 더 있 으 면 큰 성 과 를 거 둘 수 있 습 니 다.우 리 는 상기 코드 를 Vue 의$watch 방법 에 맞 춰 사용 해 야 합 니 다.watch Vue 인 스 턴 스 의 속성 을 사용 해 야 합 니 다.됐 습 니 다.제 가 무슨 말 을 하 는 지 신경 쓰 지 말고 코드 를 직접 보 세 요.

import Watcher from '../watcher'
import {observe} from "../observer"

export default class Vue {
 constructor (options={}) {
 //     。。   merge
 this.$options=options
 //     。。      
 let data = this._data=this.$options.data
 Object.keys(data).forEach(key=>this._proxy(key))
 observe(data,this)
 }


 $watch(expOrFn, cb, options){
 new Watcher(this, expOrFn, cb)
 }

 _proxy(key) {
 var self = this
 Object.defineProperty(self, key, {
 configurable: true,
 enumerable: true,
 get: function proxyGetter () {
 return self._data[key]
 },
 set: function proxySetter (val) {
 self._data[key] = val
 }
 })
 }
}

아주 간단 해 요.두 가지 일 은 observe 자신의 data,자신의 data 를 대리 하여 자신의 속성 에 접근 하 게 하 는 것 이 바로 하위 data 에 접근 하 는 속성 입 니 다.
지금까지 우 리 는 가장 간단 한 상황 만 을 고려 한 끝 에 전체 절차 가 마침내 뚫 렸 다.분명 많은 bug 가 있 을 것 입 니 다.본 고 는 전체 워 크 플 로 를 보 여 주 고 독자 의 이 해 를 돕 는 데 목적 을 둡 니 다.
코드 는https://github.com/georgebbbb...
저 는 만 개 입 니 다.제 코드 를 보 여주 고 싶 지 않 습 니 다.홈 이 많 기 때문에 양해 해 주 십시오.
다음 편 에 서 는 두 가지 방향 이 있 습 니 다.양 방향 연결 을 어떻게 실현 하 는 지,아니면 워 치 배열 을 어떻게 하 는 지 에 대해 이야기 하 겠 습 니 다.
vue 2.0 에 대한 새로운 글
100 줄 코드,vue 2.0 의 응답 식 구 조 를 이해 하고 분석 합 니 다.
본 고 는 이미《Vue.js 전단 구성 요소 학습 튜 토리 얼》로 정리 되 었 으 니,여러분 의 학습 과 독 서 를 환영 합 니 다.
vue.js 구성 요소 에 대한 튜 토리 얼 은 주제vue.js 구성 요소 학습 강좌를 클릭 하여 학습 하 십시오.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기