我希望提高我的JavaScript函数编程技巧。作为练习,我想移植到JS HS Teoh着名的无环日历打印输出程序 - 在其原始D实现中解释https://wiki.dlang.org/Component_programming_with_ranges,以及由Eric Niebler在C ++端口进行的精彩YouTube演讲https://youtu.be/mFUXNMfaciE
我尝试过使用JavaScript的原生迭代器和生成器https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators,并且很快就会崩溃。我觉得这些不足以完成这项任务。特别是:
我已经快速浏览了RxJs http://reactivex.io/rxjs/,以便将其用于此目的。我担心这需要大量的学习并且是非常难以理解的,并不是真的旨在解决我所遇到的问题(这不是异步问题等),而且我所知道的可能都不起作用。
我的问题是:
答案 0 :(得分:3)
JavaScript支持函数作为一流数据,因此您可以轻松地抽象自己的玩具。下面我们使用我们制作的抽象<head>
<base href="https://polygit.org/polymer+v2.3.1/components/">
<script src="webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-icons/iron-icons.html">
<link rel="import" href="iron-icon/iron-icon.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
x-suggestions {
width: 350px;
}
</style>
<x-suggestions suggestions="[[suggestions]]"></x-suggestions>
</template>
</dom-module>
<dom-module id="x-suggestions">
<template>
<style>
:host {
display: block;
background: #f8f8f8;
color: #6a6a6a;
padding-bottom: 1rem;
}
.title {
margin: 0;
padding: 1rem 1rem 1rem 1.3rem;
}
.feedback {
text-decoration: none;
font-style: italic;
color: #6a6a6a;
margin: 1rem;
}
.suggestion {
text-decoration: none;
font-weight: bold;
color: black;
}
.suggestions-outer {
overflow-x: auto;
}
.suggestions-inner {
white-space: nowrap;
}
.suggestion-box {
display: inline-flex;
margin: 0.2rem;
padding: 1em 1em 1em 0.5em;
border: solid 1px #ddd;
border-radius: 2px;
}
.header {
display: flex;
border-top: solid 2px #e9e9e9;
}
.close-btn {
background: transparent;
border: none;
margin: 10px 10px 10px auto;
font-size: 1rem;
color: #6a6a6a;
cursor: pointer;
}
.icon-search {
color: #717171;
--iron-icon-height: 28px;
--iron-icon-width: 28px;
}
</style>
<header class="header">
<h3 class="title">People also search for</h3>
<button class="close-btn" title$="Close" on-click="_onClickClose">✕</button>
</header>
<div class="suggestions-outer">
<div class="suggestions-inner">
<template is="dom-repeat" items="[[suggestions]]">
<div class="suggestion-box">
<a class="suggestion" target$="_blank" href$="[[item.url]]">
<iron-icon class="icon-search" icon="search"></iron-icon>
<span>[[item.title]]</span>
</a>
</div>
</template>
<a href="#" class="feedback" on-click="_onClickFeedback">Feedback</a>
</div>
</div>
</template>
</dom-module>
</body>
和Yield
来创建我们自己的persistent(不可变)迭代器。 Memoization用于避免重复计算迭代器的下一个值。
我们的持久迭代器的行为几乎与它们的原生JS对应物一样,只有它们是不可变的! Return
,done
和value
属性应该让您感到熟悉。
next
但是你不打算通过使用赋值迭代迭代器,递归正是我们在这里需要的
const Memo = (f, memo) => () =>
memo === undefined
? (memo = f (), memo)
: memo
const Yield = (value, next = Return) =>
({ done: false, value, next: Memo (next) })
const Return = value =>
({ done: true, value })
const Range = (min = 0, max = Infinity) =>
min > max
? Return ()
: Yield (min, () => Range (min + 1, max))
const state0 =
Range (0, 2)
console.log (state0.done) // false
console.log (state0.value) // 0
console.log (state0.value) // 0
const state1 =
state0.next ()
console.log (state1.done) // false
console.log (state1.value) // 1
console.log (state1.value) // 1
const state2 =
state1.next ()
console.log (state2.done) // false
console.log (state2.value) // 2
console.log (state2.value) // 2
const state3 =
state2.next ()
console.log (state3.done) // true
当然,因为迭代器是持久的,我们可以多次逐步通过相同的迭代器
const MappedIterator = (f, it = Return ()) =>
it.done
? Return ()
: Yield (f (it.value), () => MappedIterator (f, it.next ()))
const Generator = function* (it = Return ())
{
while (it.done === false)
(yield it.value, it = it.next ())
return it.value
}
const square = x =>
x * x
Array.from (Generator (MappedIterator (square, Range (0, 10))))
// => [ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ]
这是一个完整的代码演示
const ConcatIterator = (x = Return (), y = Return ()) =>
x.done
? y
: Yield (x.value, () => ConcatIterator (x.next (), y))
const it =
MappedIterator (square, Range (1, 3))
Array.from (Generator (it)) // => [ 1, 4, 9 ]
Array.from (Generator (ConcatIterator (it, it))) // => [ 1, 4, 9, 1, 4, 9 ]