자바 스 크 립 트 는 어떻게 배열 의 변 화 를 모니터링 합 니까?

8958 단어 js모니터링배열
머리말
전에 define Property 소개에서 말 했 듯 이 대상 의 변화 만 모니터링 할 수 있 을 뿐 수조 의 변 화 를 모니터링 할 수 없다.
본 고 는 어떻게 감시 배열 의 변 화 를 실현 하 는 지 분명하게 말 하 는 데 주력 하고 있다.
핵심 사고:원 배열 을 바 꾸 는 방법 을 찾 아 이 방법 들 을 납치 처리 합 니 다.
위의 이 말 은 가장 중요 한 것 이 니 반드시 세 번 읽 고 기억 하고 다시 내 려 가 야 한다.
원래 배열 을 바 꾸 는 데 자주 사용 되 는 방법 은 push pop shift unshift reverse sort splice 입 니 다.
배열 의 입 구 를 바 꾸 는 것 이다.
배열 인 스 턴 스 와 배열 원형 사이 에 새로운 원형 을 추가 합 니 다.
Array.prototype 을 직접 수정 하 는 것 은 매우 위험 합 니 다.
사고방식 을 바 꾸 어 기 존의 수조 원형 을 복제 한 다음 에 그 중의 방법 을 수정 하지만 여 기 는 원형 상의 방법 이 일일이 열거 할 수 없 기 때문에 자연히 복제 할 수 없다.
그래서 생각 을 바 꾸 고 배열 과 배열 의 원형 사이 에 원형 을 삽입 하여 원형 체인 을 형성 하고 배열=>새로운 원형=>배열 의 원형 은 새로운 원형 에 동명 의 방법 을 추가 하면 된다.
먼저 의사 코드 의 이 해 를 빌려:

//    
let arr = [];
arr.__proto__ = newPrototype;
newPrototype.__proto__ = Array.prototype;
//                     
newPrototype.push = xxx;
실제 코드 로 바 꾸 면 다음 과 같 습 니 다.핵심 은 사용 되 었 습 니 다Object.create.

// Object.create       ,      __proto__        。
let newPrototype = Object.create(Array.prototype);
//                     
newPrototype.push = xxx;

//        ,          
let arr = [];
arr.__proto__ = newPrototype;
push 를 예 로 들 면,push 를 납치 합 니 다.
새로운 원형 에 push 를 다시 쓰 는 방법 입 니 다.그 안에 오래된 push 를 실행 하지만 그 밖 에 다른 일 을 할 수 있 습 니 다.

let newPrototype = Object.create(Array.prototype);

//          push
newPrototype.push = function(...args) {
  //    this
  let curArr = this;
  console.log("   push");
  //           push
  return Array.prototype.push.call(curArr, ...args);
};

//        ,          
let arr = [];
arr.__proto__ = newPrototype;

//   push   ,     
arr.push(1);
그리고 다른 방법 도 비슷 하 다.다른 방법 을 써 보 자.
다른 방법 을 납치 하 다
다른 방법 도 함께 썼 다.논리 가 같 기 때문에 직접 옮 겨 다 니 면 된다.

let newPrototype = Object.create(Array.prototype);

let methods = ["push", "pop", "shift", "unshift", "reverse", "sort", "splice"];

methods.forEach(method => {
  newPrototype[method] = function(...args) {
    console.log(`   ${method}`);
    return Array.prototype[method].call(this, ...args);
  };
});

//        ,          
let arr = [];
arr.__proto__ = newPrototype;

//      ,     
arr.push(1);
arr.pop();
배열 에 배열 항목 이 있 으 면 모니터링 이 필요 하 다.
이 배열 에 도 배열 이 있 을 수 있 습 니 다.배열 의 모든 항목 을 옮 겨 다 녀 야 합 니 다.배열 이 라면 새로운 원형 을 가 리 켜 야 합 니 다.
응,맞 아,재 귀적 으로 썼어.

let newPrototype = Object.create(Array.prototype);

let methods = ["push", "pop", "shift", "unshift", "reverse", "sort", "splice"];

methods.forEach(method => {
  newPrototype[method] = function(...args) {
    console.log(`   ${method}`);
    return Array.prototype[method].call(this, ...args);
  };
});

function observeArr(arr) {
  //       ,         
  if (!Array.isArray(arr)) {
    return;
  }
  //           
  arr.__proto__ = newPrototype;
  //      ,     ,       。
  arr.forEach(observeArr);
}
//        ,          
let arr = [[1, 2, 3]];
observeArr(arr);

//      ,     
arr[0].push(1);
arr[1].pop();
배열 에 새로 추 가 된 항목 은 배열 이 라면 새로운 원형 을 가 리 켜 야 합 니 다.
요 소 를 추가 할 수 있 는 방법:push unshift splice.
새로 추 가 된 요 소 를 찾 은 다음 배열 의 것 도 새로운 원형 을 가리 키 고 있 습 니 다.

let newPrototype = Object.create(Array.prototype);

let methods = ["push", "pop", "shift", "unshift", "reverse", "sort", "splice"];

methods.forEach(method => {
  newPrototype[method] = function(...args) {
    console.log(`   ${method}`);
    let inserted;
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        inserted = args.slice(2);
        break;
      default:
        break;
    }
    inserted && observeArr(inserted);
    return Array.prototype[method].call(this, ...args);
  };
});

function observeArr(arr) {
  //       ,         
  if (!Array.isArray(arr)) {
    return;
  }
  //           
  arr.__proto__ = newPrototype;
  //      ,     ,       。
  arr.forEach(observeArr);
}
//        ,        
export default observeArr;
//        ,          
let arr = [];
observeArr(arr);
let addItem = [1, 2, 3];
arr.push(addItem);
//      ,     
addItem.push(1);
addItem.pop();
define Property 모니터링 대상 과 배열 을 종합 적 으로 사용 합 니 다.
지금 은 모니터링 대상 의 방법 도 있 고 모니터링 수조 의 방법 도 있다.두 개 를 종합 하면 수조 안의 대상,대상 안의 수 조 를 모니터링 할 수 있다.
모니터링 배열 과 모니터링 대상 을 하나의 파일 로 작성 하여 나중에 사용 하기에 편리 하 다.
여 기 는 코드 를 직접 실행 하 는 데 편리 하도록 한 곳 에 두 었 다.

/**
 * observeArr   
 **/
//       
let newPrototype = Object.create(Array.prototype);

let methods = ["push", "pop", "shift", "unshift", "reverse", "sort", "splice"];
//             ,    
methods.forEach(method => {
  newPrototype[method] = function(...args) {
    console.log(`   ${method}`);
    let inserted;
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        inserted = args.slice(2);
        break;
      default:
        break;
    }
    inserted && observeArr(inserted);
    return Array.prototype[method].call(this, ...args);
  };
});

function observeArr(arr) {
  //   !!!     ,     
  if (Object.prototype.toString.call(arr) === "[object Object]") {
    observeObj(arr);
    return;
  }

  if (Array.isArray(arr)) {
    //           
    arr.__proto__ = newPrototype;
    //      ,     ,       。
    arr.forEach(observeArr);
  }

  //          ,     
}

/**
 * observeObj   
 **/
function observeObj(obj) {
  //       ,         ,         
  if (typeof obj !== "object" || obj == null) {
    return;
  }
  //   !!!        
  if (Array.isArray(obj)) {
    observeArr(obj);
    return;
  }
  //            
  for (let key in obj) {
    //      obj.hasOwnProperty      
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      observeKey(obj, key);
      //            ,          ,   
      observeObj(obj[key]);
    }
  }
  return obj;
}
function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    get() {
      console.log("    ", value);
      return value;
    },
    set(newValue) {
      console.log("    ", newValue);
      value = newValue;
    }
  });
}

/**
 * demo  
 **/
let data = { a: 1, b: [1, 2, { c: 2 }] };
observeObj(data);
data.a = 2;
data.b.push([2, 3]);

let arr = [{ a: "      " }, 3, 4];
observeArr(arr);
arr[0].a = 3;

결함.
물론 배열 은 방법 을 통 해 바 꾸 지 않 아 도 된다.예 를 들 어 배열 을 직접 삭제 하면 length 속성 을 직접 사용 하거나 arr[0]=xxx 로 배열 을 바 꿀 수 있다.
그러나'push','pop','shift','unshift','reverse','sort','splice'를 사용 해 야 배열 의 변 화 를 감지 할 수 있 습 니 다.
이것 도 vue 의 결함 입 니 다.물론 새 프 록 시 는 이 결함 을 제거 할 것 입 니 다.
그래서 vue 를 사용 하 는 과정 에서 가능 한 한 이상 의 방법 으로 배열 을 조작 해 야 합 니 다~~~
첨부:배열 의 모든 속성 과 방법 보기
콘 솔 에 dir([]를 입력 하면 배열 의 모든 속성 과 방법 을 볼 수 있 습 니 다.
구체 적 인 용법 은 바로 도착 할 수 있다mdn 에서 자세히 보고 사 이 드 바 를 클릭 하여 대응 하 는 방법 을 봅 니 다..

총결산
자 바스 크 립 트 가 배열 의 변 화 를 어떻게 모니터링 하 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 JS 모니터링 배열 의 변화 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기