어떻게 자바 스 크 립 트 로 배열 타성 값 라 이브 러 리 를 실현 합 니까?

6613 단어 JS타성 구 치
개술
프로 그래 밍 언어 이론 에서 타성 구 치(영어:Lazy Evaluation)는 타성 계산,게 으 름 구 치 로 번역 되 고 전기 수요 호출(call-by-need)이 라 고도 부 르 며 컴퓨터 프로 그래 밍 의 개념 으로 컴퓨터 가 해 야 할 일 을 최소 화 하 는 것 이 목적 이다.이 는 두 가지 관련 되 고 차이 가 있 는 의 미 를 가지 는데'지연 구 치'와'최소 화 구 치'라 고 할 수 있다.성능 향상 을 얻 을 수 있 는 것 을 제외 하고 타성 컴 퓨 팅 의 가장 중요 한 장점 은 무한 한 데이터 유형 을 구성 할 수 있다 는 것 이다.
함수 식 언어 에서 의 타성 구 치 를 보고 자바 스 크 립 트 로 가장 간단 한 실현 을 쓰 고 타성 구 치 를 깊이 이해 하려 고 합 니 다.두 가지 방법 을 사 용 했 는데 모두 80 줄 도 안 되 어 기본 적 인 배열 의 타성 구 치 를 실현 했다.
어떻게
타성 구 치 는 매번 값 을 구 할 때 수 치 를 되 돌려 주 는 것 이 아니 라 계산 파 라 메 터 를 포함 한 구 치 함 수 를 되 돌려 주 고 가치 있 는 것 을 사용 해 야 계산 할 수 있 습 니 다.

여러 개의 타성 조작 이 있 을 때 하나의 값 함수 체인 을 구성 하고 값 을 구 할 때마다 모든 값 함수 가 이전 값 함수 에 값 을 구 해서 값 을 되 돌려 줍 니 다.마지막 으로 계산 함수 가 종 료 될 때 종료 값 을 되 돌려 줍 니 다.

구체 적 실현
판단 값 함수 종료
매번 값 을 구 하 는 함수 가 각종 데 이 터 를 되 돌려 주기 때문에 유일무이한 값 을 사용 하여 흐름 의 완성 여 부 를 판단 하 는 표지 로 삼 아야 한다.마침 Symbol()은 새로운 symbol 을 만 들 수 있 습 니 다.값 은 다른 값 과 같 지 않 습 니 다.

const over = Symbol();

const isOver = function (_over) {
  return _over === over;
}
생 성 함수 범위
range 함 수 는 시작 과 종료 파 라 메 터 를 받 아들 여 값 을 구 하 는 함 수 를 되 돌려 주 고 값 을 구 하 는 함 수 를 실행 하여 값 을 되 돌려 주 며 종료 할 때 종료 값 을 되 돌려 줍 니 다.

const range = function (from, to) {
  let i = from;
  return function () {
    if (i < to) {
      i++
      console.log('range\t', i);
      return i
    }
    return over;
  }
}
변환 함수 map
값 함수 와 처리 함 수 를 받 아들 여 값 함수 flow 의 데 이 터 를 가 져 와 데 이 터 를 처리 하고 흐름 을 되 돌려 줍 니 다.

const map = function (flow, transform) {
  return function () {
    const data = flow();
    console.log('map\t', data);
    return isOver(data) ? data : transform(data);
  }
}
필터 함수 필터
값 을 구 하 는 함 수 를 받 아들 여 값 을 구 하 는 함수 flow 의 데 이 터 를 걸 러 내 고 일치 하 는 데 이 터 를 찾 아 되 돌려 줍 니 다.

const filter = function (flow, condition) {
  return function () {
    while(true) {
      const data = flow();
      if (isOver(data)) {
        return data;
      }
      if(condition(data)) {
        console.log('filter\t', data);
        return data;
      }
    }
  }
}
인 터 럽 트 함수 stop
값 을 구 하 는 함 수 를 받 아들 이 고 특정한 조건 에 이 르 렀 을 때 중단 하면 패 킷 함수 에 stop 함 수 를 더 해서 take 함 수 를 실현 할 수 있 습 니 다.

const stop = function (flow, condition) {
  let _stop = false;
  return function () {
    if (_stop) return over;
    const data = flow();
    if (isOver(data)) {
      return data;
    }
    _stop = condition(data);
    return data;
  }
}

const take = function(flow, num) {
  let i = 0;
  return stop(flow, (data) => {
    return ++i >= num;
  });
}
수집 함수 join
돌아 오 는 것 은 하나의 함수 이기 때문에 마지막 으로 join 함 수 를 사용 하여 모든 값 을 수집 하고 배열 을 되 돌려 야 합 니 다.

const join = function (flow) {
  const array = [];
  while(true) {
    const data = flow();
    if (isOver(data)) {
      break;
    }
    array.push(data);
  }
  return array;
}
테스트:

const nums = join(take(filter(map(range(0, 20), n => n * 10), n => n % 3 === 0), 2));
console.log(nums);
출력:
range  1
map    1
range  2
map    2
range  3
map    3
filter     30
range  4
map    4
range  5
map    5
range  6
map    6
filter     60
더욱 우아 한 실현
위 에서 함수+패 키 지 를 사용 하여 타성 구 치 를 실현 하 였 으 나 우아 하지 못 하여 대부분의 코드 는 교체 와 구 치 를 완성 하 는 지 판단 하 는 위 에 놓 여 있 습 니 다.사실 es6 에서 타성 구 치 를 실현 하 는 더 좋 은 방법 이 있다.바로 generator 를 사용 하 는 것 이다.generator 는 우리 에 게 교체 와 흐름 의 완성 여 부 를 판단 해 주 었 기 때문에 우 리 는 논리 에 전념 하여 더욱 간결 하고 알 기 쉬 운 구조 가 뚜렷 한 코드 를 쓸 수 있다.

const range = function* (from, to) {
  for(let i = from; i < to; i++) {
    console.log('range\t', i);
    yield i;
  }
}

const map = function* (flow, transform) {
  for(const data of flow) {
    console.log('map\t', data);
    yield(transform(data));
  }
}

const filter = function* (flow, condition) {
  for(const data of flow) {
    console.log('filter\t', data);
    if (condition(data)) {
      yield data;
    }
  }
}

const stop = function*(flow, condition) {
  for(const data of flow) {
    yield data;
    if (condition(data)) {
      break;
    }
  }
}

const take = function (flow, number) {
  let count = 0;
  const _filter = function (data) {
    count ++
    return count >= number;
  }
  return stop(flow, _filter);
}
체인 호출 까지 해 야 완 성 된 거 야.

class _Lazy{
  constructor() {
    this.iterator = null;
  }

  range(...args) {
    this.iterator = range(...args);
    return this;
  }

  map(...args) {
    this.iterator = map(this.iterator, ...args);
    return this;
  }

  filter(...args) {
    this.iterator = filter(this.iterator, ...args);
    return this;
  }

  take(...args) {
    this.iterator = take(this.iterator, ...args);
    return this;
  }

  [Symbol.iterator]() {
    return this.iterator;
  }

}

function lazy () {
  return new _Lazy();
}
마지막 으로 다시 한 번 테스트 해 보 자.

const nums = lazy().range(0, 100).map(n => n * 10).filter(n => n % 3 === 0).take(2);

for(let n of nums) {
  console.log('num:\t', n, '
'); }
출력:
range  0
map    0
filter     0
num:   0
range  1
map    1
filter     10
range  2
map    2
filter     20
range  3
map    3
filter     30
num:   30
자,큰 성 과 를 거 두 었 습 니 다.
총결산
이렇게 해서 우 리 는 가장 간단 한 배열 의 타성 구 치 를 완성 했다.여 기 는 타성 구 치 를 간단하게 실 현 했 을 뿐 공사 에 넣 으 려 면 많은 세부 사항 을 추가 해 야 한다.코드 가 80 줄 에 불과 하기 때문에 타성 구 치 원 리 를 잘 알 수 있 고 생 성기 에 대한 이 해 를 강화 할 수 있 습 니 다.
이상 은 어떻게 자바 스 크 립 트 로 하나의 배열 타성 구 치 라 이브 러 리 를 실현 하 는 지 에 대한 상세 한 내용 입 니 다.자바 스 크 립 트 가 배열 타성 구 치 라 이브 러 리 를 실현 하 는 지 에 관 한 자 료 는 우리 의 다른 관련 글 에 관심 을 가 져 주 십시오!

좋은 웹페이지 즐겨찾기