潇潇雨雨
这有帮助吗?var user1 = { name: 'Nady', active: true, cart: [], purchase: [],};function compose(f, g) { const composition = function(...args) { console.log('f name', f.name); console.log('g name', g.name); return f(g(...args)); }; Object.defineProperty(composition, 'name', { value: 'composition_of_' + f.name + '_and_' + g.name, writable: false }); return composition;};function userPurchase(...fns) { return fns.reduce(compose);}function addItemToCart(user, item) { return { ...user, cart: [item] };}function applayTax(user) { var { cart } = user; var taxRate = 1.3; var updatedCart = cart.map(function updateCartItem(item) { return { ...item, price: item.price * taxRate }; }); return { ...user, cart: updatedCart };}function addItemToPurchase(user) { return { ...user, purchase: user.cart };}function empty(user) { return { ...user, cart: [] };}const result = userPurchase( empty, addItemToPurchase, applayTax, addItemToCart)(user1, { name: 'laptop', price: 876 });console.log(result);假设您需要输入一个数字,加十,然后加倍。您可以编写一些函数,例如:const add_ten = function(num) { return num + 10; };const double = function(num) { return num * 2; };const add_ten_and_double = function(num) { return double(add_ten(num)); };你也可以写同样的东西:function compose(outer_function, inner_function) { return function(num) { return outer_function(inner_function(num)); };};const add_ten = function(num) { return num + 10; };const double = function(num) { return num * 2; };const add_ten_and_double = compose(double, add_ten);console.log('typeof add_ten_and_double:', typeof add_ten_and_double);console.log('add_ten_and_double:', add_ten_and_double(4));使用 compose,我们创建了一个与原始 add_ten_and_double 函数执行相同操作的函数。到目前为止这有意义吗?(A点)。如果我们决定添加五个,我们可能会得到:function compose(outer_function, inner_function) { return function(num) { return outer_function(inner_function(num)); };};const add_ten = function(num) { return num + 10; };const double = function(num) { return num * 2; };const add_five = function(num) { return num + 5; };const add_ten_and_double_and_add_five = compose(compose(add_five, double), add_ten);console.log('typeof add_ten_and_double_and_add_five :', typeof add_ten_and_double_and_add_five);console.log('add_ten_and_double_and_add_five :', add_ten_and_double_and_add_five(4));现在我们已经使用一个函数和一个由另外两个函数组成的函数运行 compose,但我们得到的仍然只是一个接受数字并返回数字的函数。到目前为止这有意义吗?(B点)。如果我们想添加更多函数,那么我们最终会在代码中进行大量 compose 调用,因此我们可以只说“给我所有这些函数的组合”,它可能看起来像:function compose(outer_function, inner_function) { return function(num) { return outer_function(inner_function(num)); };};const add_ten = function(num) { return num + 10; };const double = function(num) { return num * 2; };const add_five = function(num) { return num + 5; };functions_to_compose = [add_five, double, add_ten];let composition;functions_to_compose.forEach(function(to_compose) { if(!composition) composition = to_compose; else composition = compose(composition, to_compose);});const add_ten_and_double_and_add_five = composition;console.log('typeof add_ten_and_double_and_add_five:', typeof add_ten_and_double_and_add_five);console.log('add_ten_and_double_and_add_five:', add_ten_and_double_and_add_five(4));fns.reduce(compose); 代码中的 userPurchase 基本上与此处的 forEach 循环执行相同的操作,但更简洁。为什么 add_ten_and_double_and_add_ Five 是一个可以传入数字的函数,并且functions_to_compose 中的所有操作都应用于该数字(从最后到第一个),这是否有意义?(C点)。
HUH函数
重命名部分问题只是在于命名。引入另外一项功能并重命名另外两项功能将有所帮助。var composeTwo = function test1(f, g) { return function test2(...args) { return f(g(...args)); };};function composeMany(...fns) { return fns.reduce(composeTwo);}const userPurchase = composeMany( empty, addItemToPurchase, applyTax, addItemToCart) userPurchase(user1, { name: 'laptop', price: 876 });//=> {active: true, cart: [], name: "Nady", purchase: [{name: "laptop", price: 1138.8}]}// other functions elidedcomposeTwo(最初称为compose) 是一个函数,它接受两个函数并返回一个新函数,该函数接受一些输入,使用该输入调用第二个函数,然后使用结果调用第一个函数。这是函数的简单数学组合。composeMany(最初称为 - 非常令人困惑 - userPurchase)将此组合扩展为在函数列表上工作,从传递的参数开始reduce,按顺序调用到目前为止管道结果上的每个函数。请注意,它的工作范围是从列表中的最后一项到第一项。我们用它来定义 new userPurchase,它将empty、addItemToPurchase和传递给。这会返回一个函数,然后该函数将按顺序应用它们,执行相当于applyTaxaddItemToCartpipelinefunction (...args) {return empty1(addItemToPurchase(applyTax(addItemToCart(...args))))}我们可以在这段代码中看到它的实际效果:var user1 = { name: 'Nady', active: true, cart: [], purchase: [],};var composeTwo = function test1(f, g) { return function test2(...args) { return f(g(...args)); };};function composeMany (...fns) { return fns.reduce(composeTwo);}const userPurchase = composeMany ( empty, addItemToPurchase, applyTax, addItemToCart) console .log ( userPurchase(user1, { name: 'laptop', price: 876 }))function addItemToCart(user, item) { return { ...user, cart: [item] };}function applyTax(user) { var { cart } = user; var taxRate = 1.3; var updatedCart = cart.map(function updateCartItem(item) { return { ...item, price: item.price * taxRate }; }); return { ...user, cart: updatedCart };}function addItemToPurchase(user) { return { ...user, purchase: user.cart };}function empty(user) { return { ...user, cart: [] };}.as-console-wrapper {max-height: 100% !important; top: 0}现代语法然而,我会发现使用更现代的 JS 语法会更干净。这是非常等价的,但更干净:const composeTwo = (f, g) => (...args) => f (g (...args))const composeMany = (...fns) => fns .reduce (composeTwo)// .. other functions elidedconst userPurchase = composeMany ( empty, addItemToPurchase, applyTax, addItemToCart)很明显,这里composeTwo接受两个函数并返回一个函数。在了解和理解后.reduce,应该清楚composeMany接受一个函数列表并返回一个新函数。此版本也将此更改应用于其余功能,可在以下代码段中找到:var composeTwo = (f, g) => (...args) => f (g (...args))const composeMany = (...fns) => fns .reduce (composeTwo)const addItemToCart = (user, item) => ({ ...user, cart: [item] })const applyTax = (user) => { var { cart } = user; var taxRate = 1.3; var updatedCart = cart .map (item => ({ ...item, price: item .price * taxRate })) return { ...user, cart: updatedCart };}const addItemToPurchase = (user) => ({ ...user, purchase: user.cart })const empty = (user) => ({ ...user, cart: [] })const userPurchase = composeMany ( empty, addItemToPurchase, applyTax, addItemToCart)const user1 = { name: 'Nady', active: true, cart: [], purchase: [],};console .log ( userPurchase (user1, { name: 'laptop', price: 876 })).as-console-wrapper {max-height: 100% !important; top: 0}如何reduce以及如何composeTwo一起工作在这里,我们尝试演示如何reduce将composeTwo多个函数组合为一个函数。第一步,缺少init参数 to ,因此 JS 使用数组中的第一个值作为初始值,然后开始迭代第二个值。reduce所以reduce首先composeTwo用emptyand调用addItemToPurchase,产生一个相当于(...args) => empty (addItemsToPurchase (...args))现在reduce将该函数 和applyTax传递给compose,产生一个类似的函数(...args) => ((...args2) => empty (addItemsToPurchase (...args2))) (applyTax (...args))现在其结构如下:(x) => ((y) => f ( g (y)) (h (x))其中x代表...args、y代表...args2、f代表empty、g代表addItems、h代表applyTax。但右侧是一个函数 ( ),并对其应用了(y) => f ( g ( y))值。h (x)这与y在主体中替换为h(x), 产生相同f (g (h (x))),因此该函数相当于 (x) => f (g (h (x))),并且通过替换我们的原始值,最终结果为(...args) => empty (addItemsToPurchase (applyTax ( ...args)))请注意,在构建函数时,现在不会对函数应用值。当调用结果函数时就会发生这种情况。记忆中,这还是类似的东西(...args) => ((...args2) => empty (addItems (...args2))) (applyTax (...args))。但这个合乎逻辑的版本展示了它是如何工作的。当然,我们现在再次这样做addItemToCart:(...args) => ((...args2) => empty (addItemsToPurchase (applyTax ( ...args2)))) (addItemToCart (...args))通过同样的应用,我们得到等价的(...args) => empty (addItems (applyTax ( addItemToCart (...args))))这就是这些函数的组成的基本定义。清理税率硬编码的税率有些奇怪。我们可以通过在调用中使用参数来解决这个问题userPurchase。这也允许我们清理该applyTax函数:const applyTax = (taxRate) => ({cart, ...rest}) => ({ ... rest, cart: cart .map (item => ({ ...item, price: item .price * taxRate }))})const userPurchase = (taxRate) => composeMany ( empty, addItemToPurchase, applyTax(taxRate), addItemToCart)// ...userPurchase (1.3) (user1, { name: 'laptop', price: 876 })请注意,此参数的柯里化性质让我们选择仅应用此值来获取特定于税率的函数:const someDistrictPurchase = userPurchase (1.12) // 12% taxsomeDistrictPurchase(user, item)我们可以在另一个片段中看到这一点:var composeTwo = (f, g) => (...args) => f (g (...args))const composeMany = (...fns) => fns .reduce (composeTwo)const addItemToCart = (user, item) => ({ ...user, cart: [item] })const applyTax = (taxRate) => ({cart, ...rest}) => ({ ... rest, cart: cart .map (item => ({ ...item, price: item .price * taxRate }))})const addItemToPurchase = (user) => ({ ...user, purchase: user.cart })const empty = (user) => ({ ...user, cart: [] })const userPurchase = (taxRate) => composeMany ( empty, addItemToPurchase, applyTax(taxRate), addItemToCart)var user1 = { name: 'Nady', active: true, cart: [], purchase: []}console .log ( userPurchase (1.3) (user1, { name: 'laptop', price: 876 })).as-console-wrapper {max-height: 100% !important; top: 0}教训函数组合是函数式编程(FP)的重要组成部分。虽然拥有composeTwo和 等函数很有帮助composeMany,但如果它们具有易于理解的名称,那就更好了。(请注意,这compose是第一个的完全合法的名称。我在这里的更改只是为了使区别更清晰。)在我看来,最大的问题是作为组合函数composeMany的原始名称。userPurchase这让很多事情变得混乱。现代 JS(箭头函数、休息/扩展和解构)使代码不仅更简洁,而且通常更容易理解。