あなたの質問は、JavaScriptの使用方法についてですか?もしそうなら、私は助けることができるかもしれません。 Ramda.js libraryをチェックしましたか?これは、機能的なJSを書く素晴らしい方法です。のは、あなたの敵モデルを見てみましょう:
/* -- data model -- */
let enemyModel = {
name: "badguy1",
stats: {
health: 10,
strength: 42
},
pos: {
x: 100,
y: 101
}
};
レンズ:あなたはgetterメソッドとあなたの特定のオブジェクトのsetterメソッドを必要とするレンズを構築するためにを - 「敵」あなたのケースで。手でそれらを構築する方法は次のとおりです。
方法1:方法2独自のゲッターとセッター
const getHealth = path(['stats', 'health']);
const setHealth = assocPath(['stats', 'health']);
const healthLens = lens(getHealth, setHealth);
を作成します。 RAMDAの方便利便レンズオブジェクトの
const healthLens = lensPath(['stats', 'health']);
をあなたはレンズを作成したら、それはですそれを使用する時間。 Ramdaは、レンズを使用するための3つの機能を提供しています:view(..)
、set(..)
、およびover(..)
view(healthLens)(enemyModel); // 10
set(healthLens, 15)(enemyModel); // changes health from 10 to 15
over(healthLens, fireDamage)(enemyModel); // reduces enemyModel's health property by 10
あなたは敵の健康にfireDamage(..)
関数を適用しているので、あなたはover(..)
を使用したいと思います。また、あなたの位置座標がenemyModel内に入れ子になっているので、レンズを使ってそれらにもアクセスしたいと思うでしょう。私たちがそれをしている間に、一つとリファクタを作りましょう。isInRange(..)
参考として
は、ここで原点FNです:
// NOTE: not sure if this works as you intended it to...
function isInRange(radius, point) {
return point.x^2 + point.y^2 >= radius^2; // maybe try Math.pow(..)
}
はここで機能的なアプローチです:
/* -- helper functions -- */
const square = x => x * x;
const gteRadSquared = radius => flip(gte)(square(radius));
let sumPointSquared = point => converge(
add,
[compose(square, prop('x')),
compose(square, prop('y'))]
)(point);
sumPointSquared = curry(sumPointSquared); // allows for "partial application" of fn arguments
/* -- refactored fn -- */
let isInRange = (radius, point) => compose(
gteRadSquared(radius),
sumPointSquared
)(point);
isInRange = curry(isInRange);
は、ここでそれはenemyModelsのコレクションを扱うときにどのように見えるかです:
/* -- lenses -- */
const xLens = lensPath(['pos', 'x']);
const yLens = lensPath(['pos', 'y']);
const ptLens = lens(prop('pos'), assoc('pos'));
// since idk where 'radius' is coming from I'll hard-code it
let radius = 12;
const filterInRange = rad => filter(
over(ptLens, isInRange(rad)) // using 'ptLens' bc isInRange(..) takes 'radius' and a 'point'
);
const mapFireDamage = map(
over(healthLens, fireDamage) // using 'healthLens' bc fireDamage(..) takes 'health'
);
let newEnemies = compose(
mapFireDamage,
filterInRange(radius)
)(enemies);
これはレンズの有用性を示すのに役立ちます。ヘルパー関数はたくさんありますが、コードの終わりはスーパーセマンティックです。
最後に、この例をより読みやすくするために、Ramdaのこれらの関数を使用して範囲をフラッディングしています。私はこれを達成するためにES6分解を使用しています。方法は次のとおりです。
const {
add,
assocPath,
compose,
converge,
curry,
filter,
flip,
gte,
lens,
lensPath,
map,
over,
set,
path,
prop,
view
} = R;
// code goes below...
jsBinで試してみてください! Ramdaをサポートしています。
@DustinGetzあなたはそれをJavascriptに翻訳したいとお考えですか? –
@DustinGetz 'lens'ライブラリ(関数の関数)のスタイルで正確にやってみようとしているのですか、あるいはファーストクラスのゲッターとセッターを作成していますか? –
私の値はより深くネストされていますが、グラフはありません。深さ4と言ってください。機能の機能が必要だと思います。 –