One way to make a numeric value like 5 "chainable" is to define a method on the appropriate prototype object, such as Number.prototype
. For instance:
Number.prototype.add = function (n) {
return this + n
}
(5).add(2) // 7
5.0.add(2) // 7
5..add(2) // 7
((5).add(2) + 1).add(34) // okay! 42
The syntax above is funny because 5.add(2)
is invalid: JavaScript is expecting a number (or "nothing") after 5.
. Because this is a global side-effect (it will affect all numbers), care should be taken to avoid unexpected interactions.
The only other Another way to make "5" chain-able is to create a new Number
object (5 is not a real Number instance, even though it uses Number.prototype!) and then copy over required methods. (I used to think this was the only other way, but see KooiInc's answer -- however, I am not sure how well-defined returning a non-string from toString
is.)
function ops(a) {
return {
add: function(b) {
var res = new Number(a + b) // important!
var op = ops(res)
res.add = op.add // copy over singletons
return res
}
}
}
function number(a) {
return ops(a)
}
number(5).add(2) + 1 // 8
(number(5).add(2) + 1).add(34) // error! add is not a function
However, keep in mind this introduces subtle issues:
typeof 5 // number
typeof new Number(5) // object
5 instanceof Number // false
new Number(5) instanceof Number // true
And this is why we need a Number
(search SO for "primitives" in JavaScript):
x = 5
x.foo = "bar"
x.foo // undefined
Furthermore, in conjunction with cwolves' answer, consider:
function number (n) {
if (this === window) { // or perhaps !(this instanceof number)
return new number(n)
} else {
this.value = n
}
}
Then both new number(2)
and both number(2)
will evaluate to a new number object.
number(2).value // 2
new number(2).value // 2
number(2) instanceof number // true
new number(2) instanceof number // true
Happy coding.
res.add = op.add
did you copy the method add from ops(number) to res.add and then return it? If you do so, what happened if you have more than just one method to chain? [x] – Dissolve