SidekickJS's blog

The Value of valueOf

valueOf is a radically underused part of Javascript. It gives you some control over comparison of your custom object types within your application. This allows you to keep your code short, readable and natural - especially if you use a lot of value objects.

Any object which has a valueOf function available can play. valueOf is simple: it should return a primitive representation of the object’s value.

function Node(weight) { this.weight = weight } Node.prototype.valueOf = function() { return this.weight } var a = new Node(15) var b = new Node(10) var c = new Node(25)
assert( a > b ) assert( b < a ) assert( c > a && c > b )

Javascript will use the valueOf method whenever an object is in a position it should be converted to a primitive - comparison operations or arithmetic where other primitives are concerned, or in inequalities between objects.

assert( new Node(0) == 0 ) assert( new Node(0) == false ) assert( new Node(5) + 10 === 15 ) assert( new Node(5) + new Node(10) === 15 )

valueOf clearly affects the behaviour when explicitly comparing an object with a boolean - in contrast, it has no effect in implicit tests for truthiness. In if statements, the ! unary operator, or anywhere else that implicitly converts to a boolean, objects are simply defined as true:

assert( new Node(0) ) refute( !new Node(0) ) var noChangeToObjectTruthiness if( new Node(0) ) noChangeToObjectTruthiness = true assert( noChangeToObjectTruthiness )

Sorting

Having a numeric value for our objects keeps sorting much cleaner, as we can simply use subtraction - just like sorting numbers. This makes, for instance, code for a priority queue of nodes in a search algorithm clean and expressive.

var a = new Node(15) var b = new Node(10) var c = new Node(25) assert.equal( [a,c,b].sort(function(a,b) { return a - b }), [b,a,c] )

Limitations

Javascript is an object-oriented, not a message-passing language (I’ll write about this another time), so comparison is a primitive operation. This means we cannot control either equality comparison, or comparison with a range of types.

Equality

From the way inequality operators work with two objects having valueOf defined we’d assume that equality would be similar. Actually, objects are only equal under both the == and === operators when they are the same object. This leads to the following surprising code, where e is neither less, or more, than f, but isn’t equal to it.

var e = new Node(5) var f = new Node(5) refute( e > f ) refute( e < f ) refute( e == f ) refute( e === f )

Comparison with different types

Although we can control the value of our objects in comparison, we have no knowledge of the context: what we’re comparing the objects to. This means we can’t model comparisons with more than one type - unless you’re careful to return a value that is sensibly comparable to all the types you’d like to compare it with. This can lead to absurd comparisons:

function Person(age) { this.age = age } Person.prototype.valueOf = function() { return this.age } var g = new Node(10) var h = new Person(10) var i = new Person(5) assert( g > i ) refute( g > h )

In Ruby you can control exactly what happens on comparison via the <=> method, which is passed the object to compare. This makes it easy to allow comparisons with some objects, but throw exceptions for invalid comparisons.

 valueOf is ready to make your code better

Now you know what valueOf can and cannot do, you’ve got a shiny new tool to make your code even more beautiful!