Sara Sara - 10 months ago 58
Javascript Question

Great-great-great-great-... Example - Eloquent JS

I'm struggling with the "Great-great-great-great-..." example from the Higher Order Functions chapter in Eloquent JS. I don't understand how one of the functions creates a value from an object only containing ancestry data. Here are the functions:

function reduceAncestors(person, f, defaultValue) {
function valueFor(person) {
if (person == null)
return defaultValue;
return f(person, valueFor(byName[person.mother]),
return valueFor(person);


function sharedDNA(person, fromMother, fromFather) {
if ( == "Pauwels van Haverbeke")
return 1;
return (fromMother + fromFather) / 2;

I don't understand how valueFor(byName[person.mother]) generates a numerical value from an object like this:

"Carolus Haverbeke" : {
"name": "Carolus Haverbeke",
"sex": "m",
"born": 1832,
"died": 1905,
"father": "Carel Haverbeke",
"mother": "Maria van Brussel"}

Answer Source

If you look past the function declaration of sharedDNA, you'll see the following:

var ph = byName["Philibert Haverbeke"];
console.log(reduceAncestors(ph, sharedDNA, 0) / 4);

If you trace this up to reduceAncestors, the parameters map out to:

person -> { name: "Philibert Haverbeke", ... },
f -> sharedDNA,
defaultValue -> 0

Now, take a look at valueFor(). It always returns a number, either the defaultValue, or the result of sharedDNA, which always returns a number. This is the key: if a person has no parent, then defaultValue is used, otherwise, it generates a ratio of sharedDNA between the given relationships, or the third case, '1', if the person happens to be named "Pauels van Haverbeke".

To answer your question, "How valueFor(...) generates a numerical value from a person object", is that it simply returns the value that sharedDNA generates recursively.