Javascript 尝试将函数转换为更实用的样式
我正在学习函数式编程,我想知道重构bellow函数的最佳方法是什么,以了解最佳实践 我正在重构我制作的一个面向对象的粒子系统,这里首先是我作为一个类编写的代码:Javascript 尝试将函数转换为更实用的样式,javascript,functional-programming,refactoring,Javascript,Functional Programming,Refactoring,我正在学习函数式编程,我想知道重构bellow函数的最佳方法是什么,以了解最佳实践 我正在重构我制作的一个面向对象的粒子系统,这里首先是我作为一个类编写的代码: submitToFields(fields) { let totalAccelerationX = 0; let totalAccelerationY = 0; fields.forEach(field => { const vectorX = field.position.x - this.p
submitToFields(fields) {
let totalAccelerationX = 0;
let totalAccelerationY = 0;
fields.forEach(field => {
const vectorX = field.position.x - this.position.x;
const vectorY = field.position.y - this.position.y;
const force = Particle.calculateForce(field, vectorX, vectorY);
totalAccelerationX += vectorX * force;
totalAccelerationY += vectorY * force;
});
this.acceleration = new Vector(totalAccelerationX, totalAccelerationY);
}
- 该方法属于具有位置、速度、加速度等特性的粒子对象
- fiels是一个字段对象数组,其结构类似于{position:{x:0,y:0},mass:140,…}
- 向量是类似于{x:0,y:0}的对象
- 该方法计算粒子系统上的场(重力质量)对粒子的扰动加速度
const add = a => b => a + b;
const propX = R.prop('x');
const propY = R.prop('y');
const addVectors = (vectorA, vectorB) =>
vector(
add(propX(vectorA))(propX(vectorB)),
add(propY(vectorA))(propY(vectorB)),
);
const vector = (a, b) => ({ x: a, y: b });
const square = x => x ** 2;
const difference = a => b => a - b;
const position = item => R.prop('position', item) || 0;
const posX = item => R.prop('x', position(item)) || 0;
const posY = item => R.prop('y', position(item)) || 0;
const propMass = item => R.prop('mass', item) || 0;
const calculateForce = (mass, vectr) => {
return mass / (square(vectr.x) + square(vectr.y) + mass) ** 1.5;
};
const disturbanceAcceleration = (part, fields) => {
const partX = posX(part);
const partY = posY(part);
return fields.reduce((acc, curr) => {
const fieldX = difference(posX(curr))(partX);
const fieldY = difference(posY(curr))(partY);
const force = calculateForce(propMass(curr), vector(fieldX, fieldY));
const newVector = vector(fieldX * force, fieldY * force);
return addVectors(acc, newVector);
}, vector(0, 0));
};
下面是一个测试:
鉴于:
const part = {position:{x:0,y:0}};
const fields = [
{position:{x:100,y:100}, mass:140},
{position:{x:200,y:100}, mass:140} ,
{position:{x:150,y:300}, mass:140}];
执行:
disturbanceAcceleration(part,fields)
输出:
{x: 0.007947635786319896, y: 0.007256173830876778}
Vector.js 从基本的
向量
模块开始,我们使用对象来保存x
和y
属性,但我们确保向量操作添加
,差异
和缩放
不会改变对象;相反,总是返回一个新的向量-
const Vector = (x = 0, y = 0) =>
({ x, y })
Vector.add = (a = Vector (), b = Vector ()) =>
Vector
( a.x + b.x
, a.y + b.y
)
Vector.difference = (a = Vector (), b = Vector ()) =>
Vector
( a.x - b.x
, a.y - b.y
)
Vector.scale = ({ x, y } = Vector (), k = 1) =>
Vector
( x * k
, y * k
)
// ...
export default Vector
Field.js
然后我们构建一个字段
模块,它依赖于向量
。同样,我们确保不使用可变操作-
const Vector =
require ('./Vector')
const Field = (mass = 0, position = Vector ()) =>
({ mass, position })
Field.calculateForce = ({ mass, position:{ x, y } } = Field ()) =>
mass / (x ** 2 + y ** 2 + mass) ** 1.5
Field.disturbanceAcceleration = (origin, fields = []) =>
fields.reduce
( (acc, { mass, position }) =>
{ const v =
Vector.difference (position, origin)
const force =
Field.calculateForce (Field (mass, v))
return Vector.add
( acc
, Vector.scale (v, force)
)
}
, Vector ()
)
// ...
export default Field
现在是我们的解决方案-
import Vector from './Vector'
import Field from './Field'
const fields =
[ Field (140, Vector (100, 100))
, Field (140, Vector (200, 100))
, Field (140, Vector (150, 300))
]
Field.disturbanceAcceleration (Vector (), fields)
// { x: 0.007947635786319896, y: 0.007256173830876778 }
import { Vector, Field /*, ... */ } from ('myparticle')
// ...
默认参数的使用为我们提供了极其方便的数据类型使用。这些都是我们不认为理所当然的事情-
Vector () // { x: 0, y: 0 }
Vector () .x // 0
Vector () .y // 0
Vector (1, 2) .x // 1
Vector (1, 2) .y // 2
Field () // { mass: 0, position: { x: 0, y: 0 } }
Field () .mass // 0
Field () .position // { x: 0, y: 0 }
Field (100) .mass // 100
Field (100) .position // { x: 0, y: 0 }
Field (100, Vector (1, 2)) .mass // 100
Field (100, Vector (1, 2)) .position .x // 1
Field (100, Vector (1, 2)) .position .y // 2
myparticle.js
你可能会有很多子模块,这没关系。您可能希望将子模块组合成一个更大的模块,也许我们称之为myparticle-
然后当我们在解决方案中使用它时-
import Vector from './Vector'
import Field from './Field'
const fields =
[ Field (140, Vector (100, 100))
, Field (140, Vector (200, 100))
, Field (140, Vector (150, 300))
]
Field.disturbanceAcceleration (Vector (), fields)
// { x: 0.007947635786319896, y: 0.007256173830876778 }
import { Vector, Field /*, ... */ } from ('myparticle')
// ...
代码演示 展开下面的代码段,在您自己的浏览器中验证结果-
//向量-------------------------------------------
常数向量=(x=0,y=0)=>
({x,y})
Vector.add=(a=Vector(),b=Vector())=>
矢量
(a.x+b.x
,a.y+b.y
)
Vector.difference=(a=Vector(),b=Vector())=>
矢量
(a.x-b.x)
,a.y-b.y
)
Vector.scale=({x,y}=Vector(),k=1)=>
矢量
(x*k)
,y*k
)
//场-------------------------------------------
常量字段=(质量=0,位置=向量())=>
({质量,位置})
Field.calculateForce=({mass,position:{x,y}}}=Field())=>
质量/(x**2+y**2+质量)**1.5
Field.disturbanceAcceleration=(原点,字段=[])=>
字段。减少
((acc,{质量,位置})=>
{const v=
矢量差(位置、原点)
恒力=
Field.calculateForce(场(质量,v))
返回向量.add
(根据
,向量。比例(v,力)
)
}
,向量()
)
//演示-------------------------------------------
常量字段=
[字段(140,向量(100100))
,字段(140,向量(200100))
,字段(140,向量(150300))
]
常数结果=
Field.disturbanceAcceleration(向量(),字段)
console.log(结果)
//{x:0.007947635786319896,y:0.007256173830876778}
Vector.js
从基本的向量
模块开始,我们使用对象来保存x
和y
属性,但我们确保向量操作添加
,差异
和缩放
不会改变对象;相反,总是返回一个新的向量-
const Vector = (x = 0, y = 0) =>
({ x, y })
Vector.add = (a = Vector (), b = Vector ()) =>
Vector
( a.x + b.x
, a.y + b.y
)
Vector.difference = (a = Vector (), b = Vector ()) =>
Vector
( a.x - b.x
, a.y - b.y
)
Vector.scale = ({ x, y } = Vector (), k = 1) =>
Vector
( x * k
, y * k
)
// ...
export default Vector
Field.js
然后我们构建一个字段
模块,它依赖于向量
。同样,我们确保不使用可变操作-
const Vector =
require ('./Vector')
const Field = (mass = 0, position = Vector ()) =>
({ mass, position })
Field.calculateForce = ({ mass, position:{ x, y } } = Field ()) =>
mass / (x ** 2 + y ** 2 + mass) ** 1.5
Field.disturbanceAcceleration = (origin, fields = []) =>
fields.reduce
( (acc, { mass, position }) =>
{ const v =
Vector.difference (position, origin)
const force =
Field.calculateForce (Field (mass, v))
return Vector.add
( acc
, Vector.scale (v, force)
)
}
, Vector ()
)
// ...
export default Field
现在是我们的解决方案-
import Vector from './Vector'
import Field from './Field'
const fields =
[ Field (140, Vector (100, 100))
, Field (140, Vector (200, 100))
, Field (140, Vector (150, 300))
]
Field.disturbanceAcceleration (Vector (), fields)
// { x: 0.007947635786319896, y: 0.007256173830876778 }
import { Vector, Field /*, ... */ } from ('myparticle')
// ...
默认参数的使用为我们提供了极其方便的数据类型使用。这些都是我们不认为理所当然的事情-
Vector () // { x: 0, y: 0 }
Vector () .x // 0
Vector () .y // 0
Vector (1, 2) .x // 1
Vector (1, 2) .y // 2
Field () // { mass: 0, position: { x: 0, y: 0 } }
Field () .mass // 0
Field () .position // { x: 0, y: 0 }
Field (100) .mass // 100
Field (100) .position // { x: 0, y: 0 }
Field (100, Vector (1, 2)) .mass // 100
Field (100, Vector (1, 2)) .position .x // 1
Field (100, Vector (1, 2)) .position .y // 2
myparticle.js
你可能会有很多子模块,这没关系。您可能希望将子模块组合成一个更大的模块,也许我们称之为myparticle-
然后当我们在解决方案中使用它时-
import Vector from './Vector'
import Field from './Field'
const fields =
[ Field (140, Vector (100, 100))
, Field (140, Vector (200, 100))
, Field (140, Vector (150, 300))
]
Field.disturbanceAcceleration (Vector (), fields)
// { x: 0.007947635786319896, y: 0.007256173830876778 }
import { Vector, Field /*, ... */ } from ('myparticle')
// ...
代码演示 展开下面的代码段,在您自己的浏览器中验证结果-
//向量-------------------------------------------
常数向量=(x=0,y=0)=>
({x,y})
Vector.add=(a=Vector(),b=Vector())=>
矢量
(a.x+b.x
,a.y+b.y
)
Vector.difference=(a=Vector(),b=Vector())=>
矢量
(a.x-b.x)
,a.y-b.y
)
Vector.scale=({x,y}=Vector(),k=1)=>
矢量
(x*k)
,y*k
)
//场-------------------------------------------
常量字段=(质量=0,位置=向量())=>
({质量,位置})
Field.calculateForce=({mass,position:{x,y}}}=Field())=>
质量/(x**2+y**2+质量)**1.5
Field.disturbanceAcceleration=(原点,字段=[])=>
字段。减少
((acc,{质量,位置})=>
{const v=
矢量差(位置、原点)
恒力=
Field.calculateForce(场(质量,v))
返回向量.add
(根据
,向量。比例(v,力)
)
}
,向量()
)
//演示-------------------------------------------
常量字段=
[字段(140,向量(100100))
,字段(140,向量(200100))
,字段(140,向量(150300))
]
常数结果=
Field.disturbanceAcceleration(向量(),字段)
console.log(结果)
//{x:0.007947635786319896,y:0.007256173830876778}
当然,您可以在disturbanceAcceleration
中创建复杂构图以避免中间值。但这不会给你太多。在某种复杂程度上,中间结果有助于跟踪