Vue 감청 배열 변화 소스 분석

이전 코드 에 서 는 배열 에 대한 처 리 를 무시 하고 관심 이 필요 한 부분 에 만 관심 을 갖 고 배열 이 존재 하지 않 는 척 했다.
이 편 은 배열 의 문 제 를 고려 하기 시작 했다.
가장 쉬 운 것 부터 시작 하 다
한 가지 문 제 를 먼저 고려 하고,어떻게 배열 의 대상 변 화 를 감청 합 니까?배열 자체 와 그 중의 일반 값 을 무시 하고 대상 배열 의 대상 만 고려 합 니 다.
배열 을 옮 겨 다 니 며 배열 의 모든 대상 에 observe 방법 을 호출 합 니 다.

//               ,        
var Observer = function Observer(value) {
  this.value = value;
  this.dep = new Dep();
  //      ,       
  if(Array.isArray(value)) {
    this.observeArray(value);
  } else {
    this.walk(value);
  }
};
Observer.prototype.observeArray = function observeArray(items) {
  //         ,        getter、setter   
  for (var i = 0, l = items.length; i < l; i++) {
    observe(items[i]);
  }
};
현실 적 요구
실제 실현 에서 전례 처럼 간단 하지 않 을 것 이다.공식 문서 에서 감청 배열 에 대해 이렇게 설명 했다.
Vue 는 배열 의 돌연 변 이 를 관찰 하 는 방법 을 포함 하기 때문에 보기 업 데 이 트 를 촉발 합 니 다.이 방법 들 은 다음 과 같다.
push()、pop()、shift()、unshift()、splice()、sort()、reverse()
JavaScript 의 제한 으로 인해 Vue 는 다음 과 같은 변 경 된 배열 을 감지 할 수 없습니다.
색인 을 직접 설정 할 때,예 를 들 어 vm.items[indexOfItem]=newValue
배열 의 길 이 를 수정 할 때,예 를 들 어 vm.items.length=newLength
그래서 배열 자체 의 방법 에 대해 감청 을 해 야 한다.
자주 사용 되 는 작은 함수
def,전체 Vue 소스 코드 에서 반복 적 으로 나타 납 니 다.Object.defineProperty()를 이용 하여 obj 에 속성 key 를 정의 합 니 다.(존재 하 는 속성 key 를 수정 할 수도 있 습 니 다.)

function def(obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    //     boole  ,     ,   false
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  });
}
대상 에 그룹 추가 방법
대상 에 게 그룹 방법 을 추가 합 니 다.환경 이 proto 를 지원 하면 간단 합 니 다.대상 의 proto 를 이 그룹 으로 가리 키 면 됩 니 다.지원 되 지 않 으 면 이 방법 을 옮 겨 다 니 며 대상 에 순서대로 추가 합 니 다.숨겨 진 속성(즉,enumerable:false,in 키워드 에서 찾 을 수 없습니다):

var hasProto = '__proto__' in {};
var augment = hasProto ? protoAugment : copyAugment;

function protoAugment(target, src) {
  target.__proto__ = src;
}
function copyAugment(target, src, keys) {
  for(var i = 0; i < keys.length; i++) {
    var key = keys[i];
    def(target, key, src[key]);
  }
}

일단 쉬 운 거.

var arrayPush = {};

(function(method){
  var original = Array.prototype[method];
  arrayPush[method] = function() {
    // this             
    console.log(this);
    return original.apply(this, arguments)
  };
})('push');

var testPush = [];
testPush.__proto__ = arrayPush;
//     ,         this      testPush
// []
testPush.push(1);
// [1]
testPush.push(2);
배열 의 변 화 를 감청 하기 위해 배열 의 원형 을 위조 하 다.
공식 문서 에서 말 한 바 와 같이 감시 해 야 할 것 은 push(),pop(),shift(),unshift(),splice(),sort(),reverse()7 가지 방법 밖 에 없다.이 7 가지 방법 은 두 가지 로 나 눌 수 있다.
1.push(),unshift(),splice()세 가지 가 배열 에 새로운 요 소 를 추가 할 수 있 는 방법 입 니 다.
2.나머지 는 원 소 를 추가 하지 않 는 방법 입 니 다.
전역 을 오염 시 키 지 않도록 Array.prototype 을 원형 으로 하 는 대상 을 새로 만 든 다음 이 대상 자체 에 속성 을 추가 한 다음 에 이 새로 만 든 대상 을 원형 으로 하거나 Observer 의 value 에 속성 으로 추가 하여 변 화 를 감시 하 는 목적 을 달성 합 니 다.

var arrayProto = Array.prototype;
var arrayMethods = Object.create(arrayProto);
다음은 업데이트 가 필요 한 몇 가지 방법 을 옮 겨 다 니 며 array Methods 에 순서대로 추가 합 니 다.

['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(method) {
  //            
  var original = arrayProto[method];
  //   arrayMethods       method,   method    (  )
  //     arrayMethods         
  def(arrayMethods, method, function mutator() {
    var arguments$1 = arguments;

    var i = arguments.length;
    var args = new Array(i);
    //      arguments        
    //      [].slice.call(arguments)?
    while(i--) {
      args[i] = arguments$1[i];
    }
    var result = original.apply(this, args);
    //   arrayMethods       Observer    value            ,      this        Observer    value
    //   ,      Observer,      value       Observer      ,__ob__,         
    var ob = this.__ob__;
    //          
    var inserted;
    //                  
    switch(method) {
      case 'push':
        inserted = args;
        break;
      case 'unshift':
        inserted = args;
        break;
      case 'splice':
        // splice                 
        inserted =args.slice(2);
        break;
    }
    if(inserted) {
      //         getter、setter   
      ob.observerArray(inserted);
    }
    //     
    ob.dep.notify();
    return result;
  });
};

var arrayKeys = Object.getOwnPropertyNames(arrayMethods);

Observer 업데이트
상기 코드 의 주석 에 따라 Observer 를 바 꾸 어 이들 을 연결 시 켜 서 배열 변 화 를 감청 하 는 목적 을 달성 합 니 다.

var Observer = function Observer(value) {
  this.value = value;
  this.dep = new Dep();
  def(value, '__ob__', this);
  //      ,       
  if(Array.isArray(value)) {
    var argument = hasProto ? protoAugment : copyAugment;
    argument(value, arrayMethods, arrayKeys);
    this.observeArray(value);
  } else {
    this.walk(value);
  }
};
참고 자료:
vue 초기 소스 학습 시리즈 2:한 배열 의 변 화 를 어떻게 감청 합 니까?
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기