js配列メソッドreduceの古典的な使用法

小云云
リリース: 2018-01-09 09:04:22
オリジナル
2082 人が閲覧しました

JavaScript 配列には非常に多くのメソッドがありますが、なぜ reduce メソッドを取り上げるのでしょうか? 理由の 1 つは、このメソッドについて十分に理解していないためです。一方で、多くの場面で魔法のような役割を果たしてくれるこの手法に、大きな魅力も感じています。この記事では、主に js 配列メソッドの reduce に関する古典的なコード スニペットを多数まとめています。これにより、reduce の例の使用法をよりよく理解できるようになります。一緒に勉強しましょう。皆さんのお役に立てれば幸いです。 reduce方法,一个原因是我对这个方法掌握不够,不能够用到随心所欲。另一个方面,我也感觉到了这个方法的庞大魅力,在许多的场景中发挥着神奇的作用。本文主要给大家整理了很多关于js数组方法reduce的经典代码片段,能够让大家更好的理解reduce的实例用法,一起学习下吧。希望能帮助到大家。

以下是个人在工作中收藏总结的一些关于javascript数组方法reduce的相关代码片段,后续遇到其他使用这个函数的场景,将会陆续添加,这里作为备忘。

理解reduce函数

reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。


arr.reduce([callback, initialValue])
ログイン後にコピー

看如下例子:


let arr = [1, 2, 3, 4, 5];

// 10代表初始值,p代表每一次的累加值,在第一次为10
// 如果不存在初始值,那么p第一次值为1
// 此时累加的结果为15
let sum = arr.reduce((p, c) => p + c, 10); // 25
// 转成es5的写法即为:
var sum = arr.reduce(function(p, c) {
 console.log(p);
 return p + c;
}, 10);
ログイン後にコピー

片段一:字母游戏


const anagrams = str => {
 if (str.length <= 2) {
  return str.length === 2 ? [str, str[1] + str[0]] : str;
 }
 return str.split("").reduce((acc, letter, i) => {
  return acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val));
 }, []);
}

anagrams("abc"); // 结果会是什么呢?
ログイン後にコピー

reduce负责筛选出每一次执行的首字母,递归负责对剩下字母的排列组合。

片段二:累加器


const sum = arr => arr.reduce((acc, val) => acc + val, 0);
sum([1, 2, 3]);
ログイン後にコピー

片段三:计数器


const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);
countOccurrences([1, 2, 3, 2, 2, 5, 1], 1);
ログイン後にコピー

循环数组,每遇到一个值与给定值相等,即加1,同时将加上之后的结果作为下次的初始值。

片段四:函数柯里化

函数柯里化的目的就是为了储存数据,然后在最后一步执行。


const curry = (fn, arity = fn.length, ...args) => 
 arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);
curry(Math.pow)(2)(10);
curry(Math.min, 3)(10)(50)(2);
ログイン後にコピー

通过判断函数的参数取得当前函数的length(当然也可以自己指定),如果所传的参数比当前参数少,则继续递归下面,同时储存上一次传递的参数。

片段五:数组扁平化


const deepFlatten = arr => 
 arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []);
deepFlatten([1, [2, [3, 4, [5, 6]]]]);
ログイン後にコピー

片段六:生成菲波列契数组


const fibonacci = n => Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);
fibonacci(5);
ログイン後にコピー

片段七:管道加工器


const pipe = (...funcs) => arg => funcs.reduce((acc, func) => func(acc), arg);
pipe(btoa, x => x.toUpperCase())("Test");
ログイン後にコピー

通过对传递的参数进行函数加工,之后将加工之后的数据作为下一个函数的参数,这样层层传递下去。

片段八:中间件


const dispatch = action => {
 console.log(&#39;action&#39;, action);
 return action;
}
const middleware1 = dispatch => {
 return action => {
  console.log("middleware1");
  const result = dispatch(action);
  console.log("after middleware1");
  return result;
 }
}
const middleware2 = dispatch => {
 return action => {
  console.log("middleware2");
  const result = dispatch(action);
  console.log("after middleware2");
  return result;
 }
}
const middleware3 = dispatch => {
 return action => {
  console.log("middleware3");
  const result = dispatch(action);
  console.log("after middleware3");
  return result;
 }
}
const compose = middlewares => middlewares.reduce((a, b) => args => a(b(args)))

const middlewares = [middleware1, middleware2, middleware3];
const afterDispatch = compose(middlewares)(dispatch);

const testAction = arg => {
 return { type: "TEST_ACTION", params: arg };
};
afterDispatch(testAction("1111"));
ログイン後にコピー

redux中经典的compose函数中运用了这种方式,通过对中间件的重重层叠,在真正发起action的时候触发函数执行。

片段九:redux-actions对state的加工片段


// redux-actions/src/handleAction.js
const handleAction = (type, reducer, defaultState) => {
 const types = type.toString();
 const [nextReducer, throwReducer] = [reducer, reducer];
 return (state = defaultState, action) => {
  const { type: actionType } = action;
  if (!actionType || types.indexOf(actionType.toString()) === -1) {
   return state;
  }
  return (action.error === true ? throwReducer : nextReducer)(state, action);
 }
}
// reduce-reducers/src/index.js
const reduceReducer = (...reducers) => {
 return (previous, current) => {
  reducers.reduce((p, r) => r(p, current), previous);
 }
}
// redux-actions/src/handleActions.js
const handleActions = (handlers, defaultState, { namespace } = {}) => {
 // reducers的扁平化
 const flattenedReducerMap = flattenReducerMap(handles, namespace);
 // 每一种ACTION下对应的reducer处理方式
 const reducers = Reflect.ownkeys(flattenedReducerMap).map(type => handleAction(
  type,
  flattenedReducerMap[type],
  defaultState
 ));
 // 状态的加工器,用于对reducer的执行
 const reducer = reduceReducers(...reducers);
 // reducer触发
 return (state = defaultState, action) => reducer(state, action);
}
ログイン後にコピー

片段十:数据加工器


const reducers = {
 totalInEuros: (state, item) => {
  return state.euros += item.price * 0.897424392;
 },
 totalInYen: (state, item) => {
  return state.yens += item.price * 113.852;
 }
};
const manageReducers = reducers => {
 return (state, item) => {
  return Object.keys(reducers).reduce((nextState, key) => {
   reducers[key](state, item);
   return state;
  }, {})
 }
}
const bigTotalPriceReducer = manageReducers(reducers);
const initialState = { euros: 0, yens: 0 };
const items = [{ price: 10 }, { price: 120 }, { price: 1000 }];
const totals = items.reduce(bigTotalPriceReducer, initialState);
ログイン後にコピー

片段十一:对象空值判断


let school = {
 name: &#39;Hope middle school&#39;,
 created: &#39;2001&#39;,
 classes: [
  {
   name: &#39;三年二班&#39;,
   teachers: [
    { name: &#39;张二蛋&#39;, age: 26, sex: &#39;男&#39;, actor: &#39;班主任&#39; },
    { name: &#39;王小妞&#39;, age: 23, sex: &#39;女&#39;, actor: &#39;英语老师&#39; }
   ]
  },
  {
   name: &#39;明星班&#39;,
   teachers: [
    { name: &#39;欧阳娜娜&#39;, age: 29, sex: &#39;女&#39;, actor: &#39;班主任&#39; },
    { name: &#39;李易峰&#39;, age: 28, sex: &#39;男&#39;, actor: &#39;体育老师&#39; },
    { name: &#39;杨幂&#39;, age: 111, sex: &#39;女&#39;, actor: &#39;艺术老师&#39; }
   ]
  }
 ]
};
// 常规做法
school.classes &&
school.classes[0] &&
school.classes[0].teachers &&
school.classes[0].teachers[0] &&
school.classes[0].teachers[0].name
// reduce方法
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x] ? xs[x] : null), o);
get([&#39;classes&#39;, 0, &#39;teachers&#39;, 0, &#39;name&#39;], school); // 张二蛋
ログイン後にコピー

片段十二:分组


const groupBy = (arr, func) =>
arr.map(typeof func === &#39;function&#39; ? func : val => val[func]).reduce((acc, val, i) => {
 acc[val] = (acc[val] || []).concat(arr[i]);
 return acc;
}, {});
groupBy([6.1, 4.2, 6.3], Math.floor); 
groupBy([&#39;one&#39;, &#39;two&#39;, &#39;three&#39;], &#39;length&#39;);
ログイン後にコピー

首先通过map计算出所有的键值,然后再根据建值进行归类

片段十三:对象过滤


const pick = (obj, arr) =>
arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
ログイン後にコピー

根据给出的键值来遍历,比较对象中是否存在相同键值的的值,然后通过逗号表达式把赋值后的对象赋给下一个的初始值

片段十四:数组中删除指定位置的值


const remove = (arr, func) =>
 Array.isArray(arr)
 ? arr.filter(func).reduce((acc, val) => {
   arr.splice(arr.indexOf(val), 1);
   return acc.concat(val);
 }, []) : [];
const arr = [1, 2, 3, 4];
remove(arr, n => n % 2 == 0);
ログイン後にコピー

首先根据filter函数过滤出数组中符合条件的值,然后使用reduce

以下は、私が仕事で収集してまとめた JavaScript 配列メソッド reduce に関するいくつかの関連コード スニペットです。この関数が使用される他のシナリオに遭遇したときに、順次追加していきます。メモとしてです。

reduce 関数を理解しますreduce() メソッドはアキュムレータ (アキュムレータ) として関数を受け取り、配列内の各値 (左から右) が減少し始め、最終的に値になります。


const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());
const delay = d => new Promise(r => setTimeout(r, d));
const print = args => new Promise(r => r(args));
runPromisesInSeries([() => delay(1000), () => delay(2000), () => print(&#39;hello&#39;)]);
ログイン後にコピー

次の例を見てください:

const orderBy = (arr, props, orders) =>
 [...arr].sort((a, b) =>
  props.reduce((acc, prop, i) => {
   if (acc === 0) {
    const [p1, p2] = orders && orders[i] === &#39;desc&#39; ? [b[prop], a[prop]] : [a[prop], b[prop]];
    acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0;
   }
   return acc;
  }, 0)
 );
const users = [{ name: &#39;fred&#39;, age: 48 }, { name: &#39;barney&#39;, age: 36 }, { name: &#39;fly&#39;, age: 26 }];
orderBy(users, [&#39;name&#39;, &#39;age&#39;], [&#39;asc&#39;, &#39;desc&#39;]); 
orderBy(users, [&#39;name&#39;, &#39;age&#39;]);
ログイン後にコピー

フラグメント 1: Alphabet Game

const select = (from, selector) =>
 selector.split(&#39;.&#39;).reduce((prev, cur) => prev && prev[cur], from);
const obj = { selector: { to: { val: &#39;val to select&#39; } } };
select(obj, &#39;selector.to.val&#39;);
ログイン後にコピー
reduce は、次の最初の文字をフィルタリングして除去します。各実行では再帰的に残りの文字の配置と組み合わせを担当します。


フラグメント 2: アキュムレーター

rrreee

フラグメント 3: Counter

🎜🎜🎜🎜🎜rrreee🎜🎜🎜 値が等しいたびに配列をループします与えられた値、つまり、 1 を加算し、加算結果を次の初期値として使用します。 🎜🎜🎜🎜フラグメント 4: 関数カリー化🎜🎜🎜🎜関数カリー化の目的は、データを保存し、最後のステップでそれを実行することです。 🎜🎜🎜🎜rrreee🎜 関数のパラメーターを判断して、現在の関数の length を取得します (もちろん、渡されたパラメーターが現在のパラメーターより小さい場合は、続行します)。以下を再帰的に実行し、渡された前回のパラメータを保存します。 🎜🎜🎜🎜フラグメント 5: 配列の平坦化🎜🎜🎜🎜🎜🎜rrreee🎜🎜🎜 フラグメント 6: Fibo Reci 配列の生成🎜🎜🎜🎜🎜🎜rrreee🎜🎜🎜 フラグメント 7:パイププロセッサー🎜 🎜🎜🎜🎜 🎜rrreee🎜作成者渡されたパラメータに対して関数処理を実行し、処理されたデータを次の関数のパラメータとして使用して、レイヤーごとに渡されます。 🎜🎜🎜🎜フラグメント 8: ミドルウェア🎜🎜🎜🎜🎜🎜rrreee🎜 🎜

redux これは、古典的な compose 関数で使用されます。つまり、アクションが実際に開始されるときに、複数のミドルウェア層を通じて関数の実行がトリガーされます。 🎜

🎜🎜フラグメント 9: 状態の Redux アクション処理🎜🎜🎜🎜🎜🎜rrreee

🎜🎜フラグメント 10: データプロセッサ🎜🎜🎜🎜🎜 🎜rrreee🎜🎜フラグメント 11: オブジェクトの null 値判定🎜🎜🎜🎜🎜🎜rrreee

🎜🎜フラグメント 12: グループ化🎜🎜🎜🎜🎜🎜rrreeeまず、map を通じてすべてのキー値を計算し、作成された値に従って分類します🎜

🎜🎜フラグメント 13: オブジェクト フィルタリング🎜 🎜🎜🎜🎜rrreee🎜指定されたキー値に従ってトラバースし、オブジェクト内に同じキー値を持つ値があるかどうかを比較し、割り当てられたオブジェクトをカンマ式を通じて次のオブジェクトに代入します。 初期値🎜🎜🎜🎜フラグメント 14: 配列内の指定された位置にある値を削除します 🎜🎜🎜🎜🎜🎜rrreee🎜 🎜🎜まず、filterに従って配列内の修飾された値をフィルタリングします。 > 関数を使用し、reduce を使用して元の配列内の修飾された値を削除します。 arr の最終値は [1, 3] になると結論付けることができます🎜🎜🎜🎜 フラグメント 15: 約束は次のとおりです。順番に実行🎜🎜🎜🎜🎜🎜rrreee🎜🎜🎜クリップ16: 並べ替え🎜🎜🎜🎜🎜🎜クリップ17: 選択🎜🎜🎜🎜🎜🎜 🎜関連する推奨事項: 🎜🎜🎜MongoDB での MapReduce の使用🎜 🎜🎜🎜指定された配列オブジェクトからjsのreduce()を確認します🎜🎜

JavaScriptの配列Reduce()関数の使い方とヒント

以上がjs配列メソッドreduceの古典的な使用法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート