Memoize a prototype method - javascript

I'm trying to use memoization to speed up my Javascript, but I need it on a proto method, and I need said method to have access to the this object, and it's giving me fits. Here's what I have:
MyObj.prototype.myMethod = function(){
var self = this
, doGetData = (function() {
var memo = []
, data = function(obj) {
var result = memo;
if (obj.isDirty) {
obj.isDirty = false;
result = $.map(obj.details, function(elem, i) {
return elem.export();
});
memo = result;
}
return result;
}
return data;
}())
;
return doGetData(self);
};
I can get it to run, I just can't get it to memoize. I know something is wrong, but I can't figure out what. I know there are tons of examples of how to memoize, but none that I've come across deal with scope like this.

If you want the function on the prototype, but you want it to memoize for each instance independently, then "memo" needs to be an instance property (or a closure could be the instance property, I guess; whichever).
MyObj.prototype.myMethod = function() {
if (!("memo" in this) || this.isDirty) {
this.isDirty =false;
this.memo = $.map(obj.details, function(elem, i) {
return elem.export();
});
}
return this.memo;
};
I don't think you can do it without polluting the instances, though you could use newer JavaScript features to keep the "memo" thing from being enumerable. The prototype is shared by all instances, after all.

It is possible to use a Map object for storing and retrieving method caches for all instances. Maps support objects as keys. (Kind of off-topic, but strict mode affects the propagation of "this". Now this works without "var self = this;".)
"use strict";
MyObj.prototype.myMethod = function() {
var prototypeCache = new Map();
return function(arg) {
if (!prototypeCache.has(this)) prototypeCache.set(this, new Map());
var instanceCache = prototypeCache.get(this);
if (instanceCache.has(arg)) return instanceCache.get(arg);
else {
//Do expensive calculation that is stored in result...
instanceCache.set(arg, result);
return result;
}
};
}();
Now for simplicity I also used a Map for the instanceCache. For speed one would typically use just an object. It depends on the keys one can make. It is typically possible to find a way to store by unique strings. (Numbers can be converted, Objects can have id strings and state/version properties, multiple arguments can be concatenated into one string...)
Another solution entirely is to create the method in the constructor instead of having it in the prototype. But that is just as bad pollution as having method caches in instance properties. Much worse, I think.

Related

Disable property mutation in JS

I was creating a component and was trying to break my implementation. The idea is to not allow user to manipulate the exposed properties.
The implementation was like this:
function MyClass(){
var data = [];
Object.defineProperty(this, 'data', {
get: function(){ return data; },
set: function(){ throw new Error('This operation is not allowed'); },
configurable: false,
});
}
var obj = new MyClass();
try {
obj.data = [];
} catch(ex) {
console.log('mutation handled');
}
obj.data.push('Found a way to mutate');
console.log(obj.data)
As you see, setting the property is handled but user is still able to mutate it using .push. This is because I'm returning a reference.
I have handled this case like:
function MyClass(){
var data = [];
Object.defineProperty(this, 'data', {
get: function(){ return data.slice(); },
set: function(){ throw new Error('This operation is not allowed'); },
configurable: false,
});
}
var obj = new MyClass();
try {
obj.data = [];
} catch(ex) {
console.log('mutation handled');
}
obj.data.push('Found a way to mutate');
console.log(obj.data)
As you see, I'm returning a new array to solve this. Not sure how it will affect performance wise.
Question: Is there an alternate way to not allow user to mutate properties that are of type object?
I have tried using writable: false, but it gives me error when I use it with get.
Note: I want this array to mutable within class but not from outside.
Your problem here is that you are effectively blocking attempts to modify MyClass. However, other objects members of MyClass are still JavaScript objects. That way you're doing it (returning a new Array for every call to get) is one of the best ways, though of course, depending of how frequently you call get or the length of the array might have performance drawbacks.
Of course, if you could use ES6, you could extend the native Array to create a ReadOnlyArray class. You can actually do this in ES5, too, but you lose the ability to use square brackets to retrieve the value from a specific index in the array.
Another option, if you can avoid Internet Explorer, is to use Proxies (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy).
With a proxy, you can trap calls to get properties of an object, and decide what to return or to do.
In the example below, we create a Proxy for an array. As you see in the handler, we define a get function. This function will be called whenever the value of a property of the target object is accessed. This includes accessing indexes or methods, as calling a method is basically retrieving the value of a property (the function) and then calling it.
As you see, if the property is an integer number, we return that position in the array. If the property is 'length' then we return the length of the array. In any other case, we return a void function.
The advantage of this is that the proxyArray still behaves like an array. You can use square brackets to get to its indexes and use the property length. But if you try to do something like proxyArray.push(23) nothing happens.
Of course, in a final solution, you might want decide what to do based on which
method is being called. You might want methods like map, filter and so on to work.
And finally, the last advantage of this approach is that you keep a reference to the original array, so you can still modify it and its values are accessible through the proxy.
var handler = {
get: function(target, property, receiver) {
var regexp = /[\d]+/;
if (regexp.exec(property)) { // indexes:
return target[property];
}
if (property === 'length') {
return target.length;
}
if (typeof (target[property]) === 'function') {
// return a function that does nothing:
return function() {};
}
}
};
// this is the original array that we keep private
var array = [1, 2, 3];
// this is the 'visible' array:
var proxyArray = new Proxy(array, handler);
console.log(proxyArray[1]);
console.log(proxyArray.length);
console.log(proxyArray.push(32)); // does nothing
console.log(proxyArray[3]); // undefined
// but if we modify the old array:
array.push(23);
console.log(array);
// the proxy is modified
console.log(proxyArray[3]); // 32
Of course, the poblem is that proxyArray is not really an array, so, depending on how you plan to use it, this might be a problem.
What you want isn't really doable in JavaScript, as far as I'm aware. The best you can hope for is to hide the data from the user as best you can. The best way to do that would be with a WeakMap
let privateData = new WeakMap();
class MyClass {
constructor() {
privateData.set(this, {
data: []
});
}
addEntry(entry) {
privateData.get(this).data.push(entry);
}
getData() {
return privateData.get(this).data.concat();
}
}
So long as you never export privateData don't export from the module, or wrap within an IIFE etc.) then your MyClass instances will be able to access the data but external forces can't (other than through methods you create)
var myInstance = new MyClass();
myInstance.getData(); // -> []
myInstance.getData().push(1);
myInstance.getData(); // -> []
myInstance.addEntry(100);
myInstance.getData(); // -> [100]

Is it possible to safely mix javascript class styles in an inheritance tree

I have picked up a piece of software which is fairly old and it has this form of "class" definition
function thisThing(parm1, parm2)
{
var self = new BaseThing(parm1);
self.val2 = parm2;
self.function2 = function() { ... }
return self;
}
I'd like to convert the whole hierachy to use the thisThing.prototype style of class, something like this
function thisThing(parm1, parm2)
{
var self = new BaseThing(parm1);
self.val2 = parm2;
return self;
}
thisThing.prototype = Object.create(BaseThing.prototype);
thisThing.prototype.constructor = thisThing;
thisThing.prototype = {
function2() { ... }
}
but I'm not sure if it is safe to mix the two styles.
Do I have to convert the whole hierarchy at once? Or can I do it a class at a time, and in which case do I need to do it top up, bottom down, or can I do it in the order I come across classes?
A note: Please don't suggest using ES6 classes, as they are not available in my current environment.
You've said that the old thisThing is called via new, which is good news in terms of whether you can mix things together (although we could work around it if not).
What you've shown as your desired form is quite non-standard, and thisThing.prototype is never used in it. I'm going to assume you mean you want to use standard constructor functions, which look like this:
function ThisThing(parm1, parm2) {
BaseThing.call(this, parm1);
this.parm2 = parm2;
}
ThisThing.prototype = Object.create(BaseThing.prototype);
ThisThing.prototype.constructor = ThisThing;
ThisThing.prototype.someMethod = function() {
// ...
};
Based on what you have in the question, you can go ahead and do that. (I do recommend the change in capitalization, it's the overwhelming standard for constructor functions.)
If there's any chance code might be calling it without new, you can make it tolerate that by detecting what's happened and handing off to new in the constructor:
function ThisThing(parm1, parm2) {
if (!(this instanceof ThisThing)) {
// Called without `new`; handle it
return new ThisThing(parm1, parm2);
}
BaseThing.call(this, parm1);
this.parm2 = parm2;
}
// ...
The thisThing you showed was using BaseThing as a constructor, so I assume (from that and the name) that it's already using the constructor pattern above.
You should be able to replace it like this. The only issue might be setting the param1 is a new BaseThing, so you might need to modify your old code.
by doing this you are using prototypical inheritance to get the methods of BaseThing.
Conversion like this can be mixed with your existing code with no problems so you can change one class at a time.
function ThisThing(param1, param2) {
this.val1 = param1
this.val2 = param2
}
ThisThing.prototype = new BaseThing
ThisThing.prototype.function2 = function() {}
var thing = new ThisThing(1, 2)
console.log(
thing instanceof BaseThing, // => true
thing instanceof ThisThing // => true
)

Inherit objects. Iterate through all objects

Here is my problem:
I have an inherit objects(class) function, which I populate with x many objects, like so:
function Booking (doc_id, arrival_date, supplier_amount, client_amount, currency, profit, calculated_profit, currency_rate) {
this.doc_id = doc_id;
this.arrival_date = arrival_date;
this.supplier_amount = supplier_amount;
this.client_amount = client_amount;
this.currency = currency;
this.profit = profit;
this.calculated_profit = calculated_profit;
this.exchange_rate = currency_rate;
if(pastDate(this.arrival_date)) {
past_date: true;
}
else {
past_date: false;
}
}
Is it possible to iterate through all the objects?
I would like to have a function that iterates through all Booking objects, and uses the results to populate a dataTables table.
I guess the function would have to be defined by
Booking.prototype = { }
I can´t seem to find anything about this on the web. I have tried all my ideas without success.
To iterate all Booking instances, you must store references to them somewhere:
var Booking = (function() {
var instances = []; // Array of instances
function Booking(foo) {
if (!(this instanceof Booking)) return; // Called without `new`
instances.push(this); // Store the instance
this.foo = foo; // Your current code
}
Booking.prototype.whatever = function() {
// You can use `instances` here
}
return Booking;
})();
But wait: DO NOT DO THAT (unless its strictly necessary).
The code above has a big problem: since the Booking instances are referenced in instances, the garbage collector won't kill them, even if they aren't referenced anywhere else.
Therefore, each time you create an instance, you produce a memory leak.
ECMAScript 6 introduces WeakSet, which lets you store weakly held objects in a collection, so that the garbage collector will kill them if they aren't referenced anywhere else. But WeakSets aren't iterable, so they aren't useful in your case.

Object Oriented JavaScript programming

I have been trying to learn OOP with JavaScript before I start attempting to learn backbone.js.
I want to be able to data bind but I can't seem to get it to work.
I've just made a simple protoype of a budget website that you can put in a budget and input how much you've spent, and it will show if you've gone over.
function BudgetItem(spent, budget){
this.setSpent = function(spent){
this.spent = spent;
}
this.setBudget = function(budget){
this.budget = budget;
}
this.getSpent = function(){
return this.spent;
}
this.getBudget = function(){
return this.budget;
}
}
function BudgetType(type){
this.getType = function(){
return type;
}
}
BudgetType.prototype = new BudgetItem();
$(document).ready(function(){
var food = new BudgetType('food');
$('.budget').html(food.getBudget());
$('.editbudget').change(function(){
food.setBudget($('.editbudget').data())
});
})
That's my code thus far. I'm not sure if I'm doing it right. Am I supposed to extend things? Also, can someone explain how to dynamically data bind without a library?
First I'll give you some theory. A Javascript function is a dynamic object, just like Object is, and a new instance can be created using the new keyword much like you are doing in your listener. When this happens, the function itself will run as a constructor while the this keyword will be bound to the newly created object. What you're doing above then is in fact adding new properties on the fly as you're passing in their values for the first time... which is fine, but not very clear to another reader.
Now for the tricky part. Every function has a link to a "hidden" Prototype object. This is an anonymous (not accessible by name) object created by the JavaScript runtime and passed as a reference to the user object through the prototype property. This Prototype object also has a reference to the function through its constructor property. To test what I'm saying for yourself, try the following:
BudgetItem.prototype.constructor === BudgetItem // true
Putting it all together, you can now think of functions as constructors to (hidden) classes that are created for you behind the scenes, accessible through the function's prototype property. So, you could add the fields to the Prototype object directly as so:
function BudgetItem(spent) {
this.spent = spent
}
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };
Another problem is inheritance and passing parameters to the constructor. Again, your version is valid but you lose the ability to pass the spent and budget values when initializing a BudgetType. What I would do is forget prototypes and go:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.type = type;
return instance;
}
This is close to what Scott Sauyet suggested above but more powerful. Now you can pass both parameters (and more) and have a more complicated inheritance tree.
Finally, what you can do is create private (or pseudo-private, more accurately) properties by providing a getter to an otherwise automatic variable (one passed as an argument or initialised inside the function). This is a special feature of the language and it works like so:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.getType = function() {
return type;
}
return instance;
}
Now you can access the 'type' passed in the constructor by obj.getType() but cannot override the initial value. Even if you define obj.type = 'New Value' the getType() will return the initial parameter passed because it has a reference to another context which was created when the object was initialised and never got released due to the closure.
Hope that helps...
if you want all instances of objects to reference the same members/values you can use a closure:
// create a constrctor for you object wrapped in a closure
myCon = (function() {
// define shared members up here
var mySharedObj = new function () {
this.member = "a";
}();
// return the actual constructor
return function () {
this.mySharedObj = mySharedObj;
}
}());
// create two instances of the object
var a = new myCon();
var b = new myCon();
// Altering the shared object from one
a.mySharedObj.member = "b";
// Alters it for all
console.log(b.mySharedObj.member);
If you want to build objects from other objects(sort of like other languages' class whatever extends baseClass), but do not want them to share values via reference(instead a clone of values), you can use something like the following:
Object.prototype.extendsUpon = (function (_prop, _args) {
return function (base) {
for (var key in base) {
if (_prop.call(base, key)) {
this[key] = base[key];
}
}
function con(child){
this.constructor = child;
}
con.prototype = base.prototype;
this.prototype = new con(this);
this.__base__ = base.prototype;
var args = _args.call(arguments);
args.shift();
base.constructor.apply(this, args);
}
}(Object.prototype.hasOwnProperty, Array.prototype.slice));
Then to build objects ontop of objects:
// Base Object Constructor
function Fruit(name) {
this.fruitname = name;
}
Fruit.prototype.yum = function() {
return "I had an " + this.fruitname;
}
// Object constructor that derives from the Base Object
function Favorite() {
// Derive this object from a specified base object:
// #arg0 -> Object Constructor to use as base
// #arg1+ -> arguments passed to the BaseObject's constructor
this.extendsUpon(Fruit, "apple");
// From here proceed as usual
// To access members from the base object that have been over-written,
// use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();
// Outputs: "I had an apple and it was my favorite"
mmm.yum();

Javascript apply — Inheriting classes

The code below is adapted from this answer
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
ErrorMessageClass.prototype = new MessageClass();
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate());
console.log(errorB.getPrivate());
The original post did not have the MessageClass.apply(this, arguments); since the purpose was to show how inheritance can go wrong in Javascript.
My question is, is saying: ErrorMessageClass.prototype = new MessageClass(); before the ErrorMessageClass constructor has even been declared bad practice? My understanding is that calling undeclared identifiers like that causes a silent declaration to occur, with the result being placed on the global window object, which I understand is bad.
Is this form:
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
ErrorMessageClass.prototype = new MessageClass();
considered to be better practice? This link shows the code written as it was originally above, which is why I even tried it. Does this blogger know something I don't (quite likely)?
EDIT
Lots of great info in the answers below, but I did want to highlight this link which really explains things perfectly
Usually, to avoid this confusion, you would just attach the prototype after, but as Adam Rackis pointed out, function declarations are hoisted, like var statements.
However, you should not instantiate the base object as the prototype. If your base object takes arguments, what are you supposed to use? Use an empty "surrogate" constructor
// Used to setup inheritance
function surrogate () {};
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
// The key steps to creating clean inheritance
surrogate.prototype = MessageClass;
// Sets up inheritance without instantiating a base class object
ErrorMessageClass.prototype = new surrogate();
// Fix the constructor property
ErrorMessageClass.prototype.constructor = ErrorMessageClass
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
There's much more to be said. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
It works because function declarations are evaluated first. If you tried to move these classes under an object literal "namespace" the first version would fail.
I personally find the second method to be much easier to read - also, don't forget to set the sub-class' prototype.constructor property back to itself. Personally, I use an inherits() method on the Function prototype which wraps up essentially the type of code you're using here.

Categories

Resources