TLDR: Trước tiên, bạn có thể lọc mảng của mình và sau đó thực hiện bản đồ của mình nhưng điều này sẽ yêu cầu hai lượt đi trên mảng (bộ lọc trả về một mảng cho bản đồ). Vì mảng này là nhỏ, nó là một chi phí hiệu suất rất nhỏ. Bạn cũng có thể làm giảm đơn giản. Tuy nhiên, nếu bạn muốn tưởng tượng lại làm thế nào điều này có thể được thực hiện với một lần vượt qua mảng (hoặc bất kỳ kiểu dữ liệu nào), bạn có thể sử dụng một ý tưởng gọi là "bộ chuyển đổi" được Rich Hickey phổ biến.
Câu trả lời:
Chúng ta không nên yêu cầu tăng chuỗi chấm và vận hành trên mảng [].map(fn1).filter(f2)...vì cách tiếp cận này tạo ra các mảng trung gian trong bộ nhớ trên mỗireducing chức năng.
Cách tiếp cận tốt nhất hoạt động trên chức năng giảm thực tế nên chỉ có một lần truyền dữ liệu và không có mảng bổ sung.
Hàm khử là hàm được truyền vào reducevà lấy một bộ tích lũy và đầu vào từ nguồn và trả về một cái gì đó trông giống như bộ tích lũy
// 1. create a concat reducing function that can be passed into `reduce`
const concat = (acc, input) => acc.concat([input])
// note that [1,2,3].reduce(concat, []) would return [1,2,3]
// transforming your reducing function by mapping
// 2. create a generic mapping function that can take a reducing function and return another reducing function
const mapping = (changeInput) => (reducing) => (acc, input) => reducing(acc, changeInput(input))
// 3. create your map function that operates on an input
const getSrc = (x) => x.src
const mappingSrc = mapping(getSrc)
// 4. now we can use our `mapSrc` function to transform our original function `concat` to get another reducing function
const inputSources = [{src:'one.html'}, {src:'two.txt'}, {src:'three.json'}]
inputSources.reduce(mappingSrc(concat), [])
// -> ['one.html', 'two.txt', 'three.json']
// remember this is really essentially just
// inputSources.reduce((acc, x) => acc.concat([x.src]), [])
// transforming your reducing function by filtering
// 5. create a generic filtering function that can take a reducing function and return another reducing function
const filtering = (predicate) => (reducing) => (acc, input) => (predicate(input) ? reducing(acc, input): acc)
// 6. create your filter function that operate on an input
const filterJsonAndLoad = (img) => {
console.log(img)
if(img.src.split('.').pop() === 'json') {
// game.loadSprite(...);
return false;
} else {
return true;
}
}
const filteringJson = filtering(filterJsonAndLoad)
// 7. notice the type of input and output of these functions
// concat is a reducing function,
// mapSrc transforms and returns a reducing function
// filterJsonAndLoad transforms and returns a reducing function
// these functions that transform reducing functions are "transducers", termed by Rich Hickey
// source: http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html
// we can pass this all into reduce! and without any intermediate arrays
const sources = inputSources.reduce(filteringJson(mappingSrc(concat)), []);
// [ 'one.html', 'two.txt' ]
// ==================================
// 8. BONUS: compose all the functions
// You can decide to create a composing function which takes an infinite number of transducers to
// operate on your reducing function to compose a computed accumulator without ever creating that
// intermediate array
const composeAll = (...args) => (x) => {
const fns = args
var i = fns.length
while (i--) {
x = fns[i].call(this, x);
}
return x
}
const doABunchOfStuff = composeAll(
filtering((x) => x.src.split('.').pop() !== 'json'),
mapping((x) => x.src),
mapping((x) => x.toUpperCase()),
mapping((x) => x + '!!!')
)
const sources2 = inputSources.reduce(doABunchOfStuff(concat), [])
// ['ONE.HTML!!!', 'TWO.TXT!!!']
Tài nguyên: bài chuyển đổi hickey phong phú