自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何用JavaScript實(shí)現(xiàn)一個(gè)數(shù)組惰性求值庫

開發(fā) 前端
在編程語言理論中,惰性求值(英語:Lazy Evaluation),又譯為惰性計(jì)算、懶惰求值,也稱為傳需求調(diào)用(call-by-need),是一個(gè)計(jì)算機(jī)編程中的一個(gè)概念,它的目的是要最小化計(jì)算機(jī)要做的工作。它有兩個(gè)相關(guān)而又有區(qū)別的含意,可以表示為“延遲求值”和“最小化求值”,除可以得到性能的提升外,惰性計(jì)算的最重要的好處是它可以構(gòu)造一個(gè)無限的數(shù)據(jù)類型。

在編程語言理論中,惰性求值(英語:Lazy Evaluation),又譯為惰性計(jì)算、懶惰求值,也稱為傳需求調(diào)用(call-by-need),是一個(gè)計(jì)算機(jī)編程中的一個(gè)概念,它的目的是要最小化計(jì)算機(jī)要做的工作。它有兩個(gè)相關(guān)而又有區(qū)別的含意,可以表示為“延遲求值”和“最小化求值”,除可以得到性能的提升外,惰性計(jì)算的最重要的好處是它可以構(gòu)造一個(gè)***的數(shù)據(jù)類型。

看到函數(shù)式語言里面的惰性求值,想自己用 JavaScript 寫一個(gè)最簡實(shí)現(xiàn),加深對(duì)惰性求值了解。用了兩種方法,都不到 80 行實(shí)現(xiàn)了基本的數(shù)組的惰性求值。

怎么實(shí)現(xiàn)

惰性求值每次求值的時(shí)候并不是返回?cái)?shù)值,而是返回一個(gè)包含計(jì)算參數(shù)的求值函數(shù),每次到了要使用值得時(shí)候,才會(huì)進(jìn)行計(jì)算。

 

[[190010]]

當(dāng)有多個(gè)惰性操作的時(shí)候,構(gòu)成一個(gè)求值函數(shù)鏈,每次求值的時(shí)候,每個(gè)求值函數(shù)都向上一個(gè)求值函數(shù)求值,返回一個(gè)值。***當(dāng)計(jì)算函數(shù)終止的時(shí)候,返回一個(gè)終止值。

具體實(shí)現(xiàn)

判斷求值函數(shù)終止

每次求值函數(shù)都會(huì)返回各種數(shù)據(jù),所以得使用一個(gè)***的值來作為判斷流是否完成的標(biāo)志。剛好 Symbol() 可以創(chuàng)建一個(gè)新的 symbol ,它的值與其它任何值皆不相等。

const over = Symbol();

const isOver = function (_over) {
  return _over === over;
}

生成函數(shù) range

range 函數(shù)接受一個(gè)起始和終止參數(shù),返回一個(gè)求值函數(shù),運(yùn)行求值函數(shù)返回一個(gè)值,終止的時(shí)候返回終止值。

const range = function (from, to) {
  let i = from;
  return function () {
    if (i < to) {
      i++
      console.log('range\t', i);
      return i
    }
    return over;
  }
}

轉(zhuǎn)換函數(shù) map

接受一個(gè)求值函數(shù)和處理函數(shù),獲取求值函數(shù) flow 中的數(shù)據(jù),對(duì)數(shù)據(jù)進(jìn)行處理,返回一個(gè)流。

const map = function (flow, transform) {
  return function () {
    const data = flow();
    console.log('map\t', data);
    return isOver(data) ? data : transform(data);
  }
}

過濾函數(shù) filter

接受一個(gè)求值函數(shù),對(duì)求值函數(shù) flow 中數(shù)據(jù)進(jìn)行過濾,找到符合的數(shù)據(jù)并且返回。

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;
      }
    }
  }
}

中斷函數(shù) stop

接受一個(gè)求值函數(shù),當(dāng)達(dá)到某個(gè)條件時(shí)中斷,可以用閉包函數(shù)加上 stop 函數(shù)接著實(shí)現(xiàn)一個(gè) take 函數(shù)。

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;
  });
}

收集函數(shù) join

因?yàn)榉祷氐亩际且粋€(gè)函數(shù),***得使用一個(gè) join 函數(shù)來收集所有的值并且返回一個(gè)數(shù)組。

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    [ 30, 60 ] */

更優(yōu)雅的實(shí)現(xiàn)

上面使用 函數(shù) + 閉包 實(shí)現(xiàn)了惰性求值,但是還是不夠優(yōu)雅,絕大部分代碼都放到迭代和判斷求值是否完成上面去了。其實(shí) es6 中還有更好方法來實(shí)現(xiàn)惰性求值,就是使用 generator,generator 已經(jīng)幫我們解決了迭代和判斷流是否完成,我們就可以專注于邏輯,寫出更簡潔易懂結(jié)構(gòu)清晰的代碼。

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);
}

還得加上鏈?zhǔn)秸{(diào)用才算是完成了。

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, '\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 */

好了,大功告成。

總結(jié)

這樣我們就完成了一個(gè)最簡的數(shù)組惰性求值的庫,這里只是簡單實(shí)現(xiàn)了惰性求值,要放到工程中還需要添加很多細(xì)節(jié)。因?yàn)榇a不過 80 行,可以很清楚的了解惰性求值原理,還能加深對(duì)生成器的理解。

***這里是 github 地址。

責(zé)任編輯:張燕妮 來源: 王大帥
相關(guān)推薦

2017-03-15 08:43:29

JavaScript模板引擎

2017-03-20 17:59:19

JavaScript模板引擎

2023-02-26 01:37:57

goORM代碼

2016-09-06 19:45:18

javascriptVue前端

2021-09-13 06:03:42

CSS 技巧搜索引擎

2020-10-26 08:19:53

算法隊(duì)列

2023-12-13 10:12:40

Python函數(shù)lambda

2023-12-30 13:33:36

Python解析器JSON

2018-06-22 10:30:56

C語言虛擬機(jī)編譯器

2022-04-14 20:43:24

JavaScript原型鏈

2018-02-25 17:30:18

2022-02-25 08:19:12

項(xiàng)目npm倉庫業(yè)務(wù)組件庫

2018-03-23 10:00:34

PythonTensorFlow神經(jīng)網(wǎng)絡(luò)

2017-10-27 22:03:35

javascrip

2012-07-17 17:05:55

JavaScript

2014-02-14 09:37:01

JavascriptDOM

2023-06-06 15:38:28

HTMLCSS開發(fā)

2020-09-02 07:22:17

JavaScript插件框架

2018-09-18 10:11:21

前端vue.jsjavascript

2021-06-25 10:38:05

JavaScript編譯器前端開發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)