简体   繁体   中英

JavaScript Functional Programming - Chaining Functions and using an anonymous function

I was doing a question on CodeWars and practicing some functional programming when I encountered a problem while trying to apply a function to a value.

So I made a pass() function that accepts a function as an argument so that I could use an anonymous function to manipulate that value and then return it. So, in this case, it takes the value from reduce and passes it to a function so it can manipulate that value then return it.

It WORKS but I really don't want to add a method to the Object prototype!

How can I do this another way while still maintaining the chaining of functions?

Simple Example

Object.prototype.pass = function(fn) {
  return fn(this);
};

var value = 1;

var new_value = value.pass(function(num){
   return num + 1;
});

console.log(value, new_value); // Outputs: 1 2

CodeWars Problem for context

 Object.prototype.pass = function(fn) { return fn(this) }; function digPow(n, p) { return n .toString() .split('') .reduce(function(total, num, i) { return total + Math.pow(parseInt(num), (p + i)) }, 0) .pass(function(total) { return (total % n == 0) ? Math.floor(total / n) : -1; }); } //digPow(89, 1) should return 1 since 8¹ + 9² = 89 = 89 * 1 console.log("Test Case 1 returns (", digPow(89, 1), ") should return 1") //digPow(92, 1) should return -1 since there is no k such as 9¹ + 2² equals 92 * k console.log("Test Case 2 returns (", digPow(92, 1), ") should return -1") //digPow(695, 2) should return 2 since 6² + 9³ + 5⁴= 1390 = 695 * 2 console.log("Test Case 3 returns (", digPow(695, 2), ") should return 2") //digPow(46288, 3) should return 51 since 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51 console.log("Test Case 4 returns (", digPow(46288, 3), ") should return 51") 

Code Wars Instructions

Some numbers have funny properties. For example:

89 --> 8¹ + 9² = 89 * 1

695 --> 6² + 9³ + 5⁴= 1390 = 695 * 2

46288 --> 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51 Given a positive integer n written as abcd... (a, b, c, d... being digits) and a positive integer p we want to find a positive integer k, if it exists, such as the sum of the digits of n taken to the successive powers of p is equal to k * n. In other words:

Is there an integer k such as : (a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k If it is the case we will return k, if not return -1.

Note: n, p will always be given as strictly positive integers.

The solution is just to not use method chaining - the functionality you want to apply to the result is not a method of it. There are various ways around:

  • A simple variable:

     function digPow(n, p) { const total = n .toString() .split('') .reduce(function(total, num, i) { return total + Math.pow(parseInt(num), (p + i)) }, 0); return (total % n == 0) ? Math.floor(total / n) : -1; } 
  • An IIFE call (this approach works better with static functions):

     function digPow(n, p) { return (function(total) { return (total % n == 0) ? Math.floor(total / n) : -1; }(n .toString() .split('') .reduce(function(total, num, i) { return total + Math.pow(parseInt(num), (p + i)) }, 0)); } 
  • The experimental bind operator (works better with static "methods" as well):

     function digPow(n, p) { return n .toString() .split('') .reduce(function(total, num, i) { return total + Math.pow(parseInt(num), (p + i)) }, 0) :: function() { return (this % n == 0) ? Math.floor(this / n) : -1; }(); } 

You also could use any of the approaches with your pass "method".

You could also use the Identity functor. This gives you a chainable interface but doesn't touch native prototypes

 const Identity = x => ({ runIdentity: x, map: f => Identity(f(x)) }) const digPow = (n, p) => Identity(n) .map(n => n.toString()) .map(str => str.split('')) .map(nums => nums.reduce((total, num, i) => total + Math.pow(parseInt(num, 10), p + i), 0)) .map(total => total % n === 0 ? Math.floor(total / n) : -1) .runIdentity console.log(digPow(89, 1)) // 1 console.log(digPow(695, 2)) // 2 


If you define some reusable functions, it cleans up the code a little bit

 const Identity = x => ({ runIdentity: x, map: f => Identity(f(x)) }) const split = x => str => str.split(x) const reduce = f => y => xs => xs.reduce(f, y) const digPow = (n, p) => Identity(n) .map(String) .map(split('')) .map(reduce((acc, x, i) => acc + Math.pow(Number(x), p + i)) (0)) .map(x => x % n === 0 ? Math.floor(x / n) : -1) .runIdentity console.log(digPow(89, 1)) // 1 console.log(digPow(695, 2)) // 2 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM