1

I'm a JS dev, experimenting with functional programming ideas, and I'm wondering if there's anyway to use chains for synchronous functions in the way the promise chains are written.

For example:

function square (num) {
  return num * num;
}
let foo = 2 
let a = square(foo) //=> 4
let b = square(square(foo)) //=> 16

Fair enough, but what I'd like to do (often to make code parsing easier) is to chain together those methods by passing that in as the first parameter of a chain. So that something like this would work:

let c = square(foo)
          .square()
          .square() //=> 256

Is there any way to do this with vanilla javascript, or is this something I'd have to modify the Function.prototype to do?

Brian Boyko
  • 613
  • 6
  • 15
  • 1
    Maybe modify the `Number` prototype and do `foo.square().square()...`? – Andrew Li May 22 '17 at 05:10
  • You mean this? http://stackoverflow.com/questions/1099628/how-does-basic-object-function-chaining-work-in-javascript – mplungjan May 22 '17 at 05:12
  • 1
    [Professor Frisby](https://egghead.io/lessons/javascript-linear-data-flow-with-container-style-types-box) might be of interest to you. –  May 22 '17 at 06:25

4 Answers4

4

You might be interested in the Identity functor – it allows you to lift any function to operate on the Identity's value – eg, square and mult below. You get a chainable interface without having to touch native prototypes ^_^

const Identity = x => ({
  runIdentity: x,
  map: f => Identity(f(x))
})

const square = x => x * x

const mult = x => y => x * y

let result = Identity(2)
  .map(square)
  .map(square)
  .map(square)
  .map(mult(1000))
  .runIdentity
  
console.log(result)
// 256000
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • 1
    map over the whole world... You know my preferences, still +1 from me :D –  May 22 '17 at 10:23
  • This might be *exactly* what I'm looking for. Though I'm not thrilled with using .map as the name of the chained function, because of possible confusion with Array.prototype.map. – Brian Boyko May 22 '17 at 14:18
  • @BrianBoyko don't worry so much ^_^ you *should* be thinking it's similar to 'Array.prototype.map' because it works the same way – `.map` takes an ordinary function, lifts it into your functor, and allows you to operate one the inner value. Array *is* a functor; just like Identity! – Mulan May 22 '17 at 18:18
  • 1
    Honestly, this has opened my eyes a bit. Time to learn some Elm – Brian Boyko May 23 '17 at 18:58
3

It is really a bad idea to modify Function.prototype or Number.prototype because you will pollute the default JavaScript objects, say: what if other framework also do the evil and add their own square?

The recommended way is to make an object by your self.

function num(v) {
    this.v = v;
    this.val = function() { return this.v; };

    this.square = function() { this.v = this.v * this.v; return this; };
    //and you can add more methods here
    this.sqrt = function() { this.v = Math.sqrt(this.v); return this; };
    return this;
}

var n = new num(2)
console.log(n.square().square().sqrt().val());
shawn
  • 4,305
  • 1
  • 17
  • 25
1

You wouldn't have to modify Function.prototype, but Number.prototype. You're trying to create a new method that acts on a number, not on a function. This does what you're trying to do:

Number.prototype.square = function() {
  return this * this;
}

let x = 4;

let y = x.square().square(); // -> 256
Arnav Aggarwal
  • 769
  • 5
  • 7
0

You can set square and num as a property of square call`

function square (num) {

  if (!this.square) {
    this.square = square;
    this.num = num || 0;
  };
  
  if (num === undefined) {
    this.num *= this.num
  }
  else if (!isNaN(num)) {  
   this.num *= num;
  };
  return this;
  
}

let foo = 2;
let c = new square(foo).square().square();
console.log(c.num);
guest271314
  • 1
  • 15
  • 104
  • 177