Hi Gary,
The numbers on initial load are not the whole picture: The first two variations with both only keep a list of PK's in memory (for most of the records in case you have many), so if you start using the FS to retrieve actual records, there will be the overhead of getting the record details from the database, while in the DataSet variant all data is already in memory. So in a real caching scenario, I expect the DataSet variant to outperform FoundSets even more than just the initial load difference.
Note that off course a DataSet is disconnected from the database, so any changes you (or another client) make are not reflected in the DataSet. You could resolve this by using the onDataBroadcast event to listen for changes in the underlying tables and update the DataSet accordingly. If done right, you can keep the cached DataSet also in memory between multiple calculation runs, so you need to get the DataSet only once per client session.
Another upside of the DataSet approach is that you can flatten your datastructure for easy processing (and again reducing back and forth's to the database to retrieve related records) and get only those columns that you actually need.
Something else I forgot to mention: your memoization approach: you store the cache against "this". But "this" for regular methods (so non-constructor functions called with the "new" keyword) points to the object they belong to. So in case of form or scope method, "this" points to the scope in which the method is declared. There is no problem dynamically adding a cache property to such a scope, but if you would have 2 memoization function in one scope, their caches would collide.
As for the example code I gave: if I copy and paste my example into a Script Editor in Servoy it works fine: no parse exceptions, no warnings and proper code completion. Which version of Servoy are you using?
The reason you cannot get it to output the name of the person is probably because you store it as this.first and you try to output this.firstName
As for not seeing the prototype in David's approach: he uses Object.create, which creates a new object with the object passed into the create function as first parameter as prototype. However, when created this way, the prototype property is not exposed (don't ask me why, it just how JavaScript is designed). You can get the prototype through Object.getPrototypeOf(yourObject). So Davids approach achieves the goal, but at the cost of having to type the object using JSDoc.
Paul