I'm trying to pass a function into a Map in the same way you would using object literal notation. Is there any way native to Immutable that could invoke the function as though you were using a getter method on an enumerable?
var person = {
firstName: 'John',
lastName: 'Smith',
format: function() {
return this.lastName + ', ' + this.firstName;
}
};
person.format(); // 'Smith, John'
var personMap = new Immutable.Map(person);
personMap.get('format'); // function() {return ... // doesn't work
I am not familiar with Immutable.js, but you can always bind the function to the proper this before it goes into the collection.
Simplest case:
person.format.bind (person);
// create immutable here
More generally, if I may presume that the collection is the only way you intend to reference the object and inherited methods are not an issue:
function objectAsCollection (object) {
var key;
for (key of Object.keys (object)) {
if (typeof object [key] == "function") {
object [key] = object [key].bind (object);
}
}
return new Immutable.Map (object);
}
This does modify the original object, but in a way that calling person.format () is not affected, and mapYouMade.get ("format")() will have this pointing at person. Some problems may arise depending on the rest of your code:
If person becomes the prototype of an object or class, the function will always behave as if this.format still refers to the prototype instead of the derived object.
If person.whateverProperty is modified, the change is not reflected in the immutable map, but theMap.get ("format")() will use the new values since it is bound to the original object, not the entries in the map, meaning that methods in the immutable would be quite mutable.
It sounds like what you want is not actually an immutable map but an immutable object; after all, collections are for homogeneous value types and methods belong on objects to which they pertain. My advise in this case would be to forget about Immutable.js and use:
Object.freeze (person);
Which makes the object itself immutable without the hazards inherent to the collection. If you simply must have a collection for some reason, you must extend the collection class and/or use proxies to get format to fetch other entries from its containing collection so that person may be mutated independently. Please comment if this is the case, I can show you how to do it, but I am not familiar with Immutable.js classes, and proxies are a complicated beast.
Related
Don't do it
This question has some comments with a low opinion of the very notion of reconstructing the objects. The commenters either couldn't or wouldn't explain why they thought it was a bad idea, but since asking I have come the to same conclusion. Here's why.
If you think about MVVM, the purpose of having a model and a view-model is to separate behaviour from data. This is kind of funny, because the point of object-orientation is to combine them. But in a distributed world, the data has to be shipped around. If your code and data are all munged together then you have to either invent MVVM or keep de- and re-constructing objects.
The code to de- and re-construct objects is a testing and maintenance time-sink you don't need, and introduces two failure modes. Don't do it. Have a method-less class to hold the state and a stateless class that operates on the method-less class. This is the essence of MVVM, and really nothing more than application of Memento pattern.
Memento (283)
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
Design Patterns, Gamma et al, 1995
Original question
The data of my view models is passed back and forth between client JS and server Web APIs as JSON.
It is well understood that JSON.stringify(object) serialises only members that have a non-null value that is not a Function. Thus, JSON.parse(JSON.stringify(someObject)) will remove all the methods from the object.
My current implementation has each graph node implemented as a Typescript class with Serialise and Deserialise methods. JQuery.ajax calls a Web API and implicitly parses the resultant JSON into a DAG of object definitions, each of which has a Type property indicating which type of class it was prior to serialisation. I have a map of constructors indexed by name and the appropriate constructor is retrieved and the data passed as the constructor parameter.
Depending on type there may be children; if so things proceed recursively down the graph.
I have been wondering whether, rather than copy all the property values, I couldn't just assign an appropriate prototype. Bring the mountain to Mahomed, you might say. This would eliminate quite a bit of clutter in my codebase.
As I write it occurs to me that I could use $.extend, but I'm progressively weeding jQuery out of my codebase so this would be a retrograde step.
Is there any known peril in my proposition of diddling the prototype?
Does anyone have a better idea? Other than $.extend, I mean. Something TypeScripty, by preference.
It has been observed in comments that assigning the prototype means the constructor is never called. This is irrelevant. The object state is already set up, all that is required is to make the methods available.
I recently built object with methods which content could be serialized and then reconstructed.
I simply added an argument which could take a JSON object and assign it to itself.
Example using plain object:
function myObject() {
this.valueA = 1;
this.valueB = 2;
this.valueC = 3;
this.add = function() {
return this.valueA + this.valueB + this.valueC;
};
}
var o = new myObject();
console.log(o.add());
console.log(JSON.stringify(o));
If you serialized this you would get:
{"valueA":1,"valueB":2,"valueC":3}
Now, to reconstruct this you can add a Object.assign() to the object like this taking the argument and merge it with self:
function myObject(json) {
this.valueA = 0;
this.valueB = 0;
this.valueC = 0;
this.add = function() {
return this.value1 + this.value2 + this.value3;
};
Object.assign(this, json); // will merge argument with itself
}
If we now pass the parsed JSON object as argument it will merge itself with the object recreating what you had:
var json = JSON.parse('{"valueA":1,"valueB":2,"valueC":3}')
function myObject(json) {
this.valueA = 0;
this.valueB = 0;
this.valueC = 0;
this.add = function() {
return this.valueA + this.valueB + this.valueC;
};
Object.assign(this, json); // will merge argument with itself
}
var o = new myObject(json); // reconstruct using original data
console.log(o.add());
If you now have children via array you simply repeat the process recursively down the chain.
(A bonus is that you can also pass options this way).
I'm trying to implement a dictionary much like Python. So, I would like to have a keys() method that returns keys added to the subclass Dict, but not properties such as the Object's method "keys"
EDIT AGAIN
Basically, I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}. It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects. So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
ie don't return this.prototype.propertyName when own is passedHere's what I have so far:
function Dict(){
this.prototype = {};
var _keys = this.prototype.keys;
this.keys = function(own){
if(typeof own === 'undefined') { return _keys(); }
var ownKeys = [];
for(var key in _keys()){
if(this.hasOwnProperty(key)) {
ownKeys.push(key);
}
}
return ownKeys;
}
}
Will this work as follows? Is there a better or already existent way to do it?
save the overloaded keys() method to a private var
return everything as usual, unless own is something that resolves to true.
if own == true, get the usual keys and filter out those
belonging to the superclass.
On the subject, I'm likely most concerned about saving back the prototype method as a way to get all of the keys and filter out proto keys.
Also, I've read overloading isn't built into Javascript. But, much of what I've found deals with standalone functions such as this Q&A on best practices. I don't need a built in way, but I'll take advantage of whatever's available (Hence, using Object as a Dict).
Any feedback is appreciated!
EDIT
In Python, we get this:
In[2]: d = {}
In[3]: 'has_key' in d.keys()
Out[3]: False
In[7]: 'has_key' in d.__class__.__dict__.keys()
Out[7]: True
In[8]: d.has_key('has_key')
Out[8]: False
In[9]: d['newKey'] = 5
In[10]: d.newKey # ERROR
Python has a dict attribute contained in its class where the functions are accessed via a dot (see In[8]...). So, those standard {} or dict() functions and operators are hidden (not private) while keys/data are added to the user's dict are accessed via []. d['newKey'] = 5 adds a new key or overwrites the old and sets the data to 5.
I don't need all of that to work, though it would be great. keys() returning Python-like keys would be fine for now.
There seem to be multiple issues here.
You seem to want to pass variable arguments to a function:
I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}.
JS function arguments are very flexible.
You can either set up names for every one of them:
function foo(arg1, arg2, map, alphaMap)
and pass values directly. This style is preferred for functions that work on a fixed set of arguments.
Or you can set up an "options" object that collects keys and values:
function foo(options)
and pass {arg1: val1, arg2: val2, map: valMap, alphaMap: valAlphaMap}. This style often occurs on constructor functions that initialize objects with a certain set configuration options.
Or you can set up an empty function signature
function foo()
and work with the arguments collection inside the function. This is found in functions that work with a variable number of uniform arguments (imagine add(1, 2, 3, 4, 6)) or strictly positional arguments instead of named ones.
In any case, passing arguments to a function is optional in JavaScript, even when there is an argument list in the function signature. You are free to pass none, less or more arguments. Of course all these approaches can be combined if it suits you.
It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects.
This is a problem caused by the asynchronous nature of the web. The solution is to use event handlers. These are either callbacks or - as an abstraction over callbacks - promises.
So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
This can be solved by not adding methods etc to data objects, or at least not directly. Add them to the prototype if your data objects must have behavior.
The direct equivalent to a Python Dict is a plain object in JavaScript.
var dict = {};
The direct equivalent of Python's keys() method is the Object.keys() static method in JavaScript.
var keys = Object.keys(dict);
To iterate the keys you can either use an imperative approach:
var i, key;
for (i = 0; i < keys.length; i++) {
key = keys[i];
doSomething(key, dict[key]);
}
or a functional one
keys.forEach(function (key) {
doSomething(key, dict[key]);
});
The direct equivalent of Python's in is .hasOwnProperty() in JavaScript:
if ( dict.hasOwnProperty('foo') ) ...
or, if it is a pure data object with no prototype chain, you can use in as well.
if ('foo' in dict)
Using in in for loops is not recommendable because it iterates the prototype properties as well. The way to guard against this is by using Object.keys() instead or by combining it with .hasOwnProperty(), as you did.
var key;
for (key in dict) {
if ( dict.hasOwnProperty(key) ) ...
}
Your question indicates that you are missing basic puzzle pieces about JS and try to substitute them with more familiar Python constructs. I would recommend not doing that.
I also suspect that you try to shoehorn Python's class-based inhertiance pattern into JS' prototype-based inheritance pattern. I strongly recommend that you don't do that, either.
I have been coding in javascript for some time, but am fairly new to Node. I recently undertook a project that involves a complex object structure with multiple levels of prototypical inheritance and sub objects. This structure needs to be periodically saved / loaded. Saving and loading in JSON is desirable.
The Question
Is there a more elegant way of accomplishing the task of saving/loading these complex Javascript objects than my current method (outlined below)? Is it possible to design it in such a way where the constructors can initialize themselves as if they were normal objects without being bound by all of the restoring functionality?
My Solution
The base 'class' (from which, by design, all other objects under consideration inherit protoypically) has a function which processes an 'options' argument, adding all of it's properties to the current object. All deriving objects must include an options argument as the last argument and call the processing function in their constructor.
Each object also must add it's function name to a specific property so that the correct constructor function can be called when the object needs to be rebuilt.
An unpack function takes the saved object JSON, creates a plain object with JSON.parse and then passes that object in as the 'options' argument to the object's constructor.
Each object is given a unique id and stored in a lookup table, so that a function under construction with links to other objects can point to the right ones, or create them if it needs to.
Here is a plunker which demonstrates the idea (obviously in a non-Node way).
If you don't want to load the plunker, here's an excerpt which should hopefully provide the gist of what I'm trying to do:
function BaseClass(name, locale, options){
if(name) this.name = name;
if(locale) this.locale = locale;
// If options are defined, apply them
this.processOptions(options);
// create the classList array which keeps track of
// the object's prototype chain
this._classList = [arguments.callee.name];
// Create a unique id for the object and add it to
// the lookup table
if(!this.id) this.id = numEntities++;
lookupTable[this.id] = this;
if(!this.relations) this.relations = [];
// other initialization stuff
}
BaseClass.prototype = {
processOptions: function(options) {
if(options && !options._processed){
for(var key in options){
if(options.hasOwnProperty(key)){
this[key] = options[key];
}
}
options._processed = true;
}
},
addNewRelation: function(otherObj){
this.relations.push(otherObj.id);
}
// Other functions and such for the base object
}
function DerivedClassA(name, locale, age, options){
if(age) this.age = age;
this.processOptions(options);
if(options && options.connectedObj){
// Get the sub object if it already exists
if(lookupTable[options.subObj.id]){
this.subObj = lookupTable[options.subObj.id];
}
// Otherwise, create it from the options
else {
this.subObj = new OtherDerivedClass(options.subObj);
}
}
else {
// If no options then construct as normal
this.subObj = new OtherDerivedClass();
}
// If something needs to be done before calling the super
// constructor, It's done here.
BaseClass.call(this, name, locale, options);
this._classList.push(arguments.callee.name);
}
DerivedClassA.prototype = Object.create(BaseClass.prototype);
As mentioned, this gets the job done, but I can't help but feeling like this could be much better. It seems to impose a ridiculous amount of restrictions on the inheriting 'classes' and how their constructors must behave. It makes a specific order of execution critical, and requires that each object be deeply involved and aware of the restoration process, which is far from ideal.
I am serializing and storing an object that was created from a WinJS.Class like this:
var myClass = WinJS.Class.define(...);
var myObject = new myClass();
var serialized = JSON.stringify(myObject);
//store the object
And later I'm pulling the object out of storage and I want to deserialize it and cast it as a myClass. Is that possible with WinJS out of the box or do I need to create a constructor for my class that is capable of taking an object that can turn it into a new object?
I haven't broken into TypeScript yet, and I think that would help out in this situation, but until then I'm wondering how to do it with plain JavaScript/WinJS.
There are a few ways to handle this, and none are particularly special to WinJS. Simply put: JSON serialization only serializes and deserializes the obje values, not its methods, prototype, or other type information.
Option 1: Copy values to new instance of your class
This is usually best accomplished by having your constructor take the deserialized object as a parameter and copying the data to the new instance.
There are a variety of variations of this. Using the object constructor is generally the best for performance, as this typically enables the JS engine to apply the greater number of optimizations to the object.
WinJS.UI.setOptions can be helpful here, or you can just copy the data using a simple loop like this:
var keys = Object.keys(source);
for (var i = 0, len = keys.length; i < len; i++) {
var key = keys[i];
destination[key] = source[key];
}
Option 2: Setting __proto__
Warning: This can have significantly adverse performance effects, so it's not appropriate in some situations. But occasionally it can be handy.
Object.setPrototypeOf(myObject, myClass.prototype);
Note that setPrototypeOf is relatively new. It's there on Win8.1 for web apps (which I'm guessing this is about) and in IE 11, but not available in Safari, for example. On older browsers/ Safari, assigning to proto is the equivalent (but if available, setPrototypeOf is better).
This will attach methods from myClass to the object, but in addition to the negative performance effects, also does not run your constructor on the object - so it still may not be in exactly the same state as the object you originally serialized.
Other helpful thing: JSON "revivers"
JSON.parse takes an optional second parameter, called a "reviver". This lets you provide a function that gets the opportunity to transform each node of the JSON being deserialized. This can be useful for rehydrating serialized dates into JavaScript Date objects, for example. It also gets the opportunity to transform the top-most object, which could be useful in some cases to turn the deserialized object into the "class" you want.
Javascript is a dynamic language so I think you dont need to cast the deserialized object, just treat it as myClass type and that's it. Hope it helps you.
You should consider using the 'Options' constructor pattern, where the option value is the deserialized object:
// MovieModel Constructor
// ----------------------
function MovieModel(options) {
this._titleValue = options.title || "Sample Title";
}
Where the movie methods closure is something like this:
// MovieModel Methods
// ------------------
var movieModelMethods = {
title: {
get: function () {
return this._titleValue;
},
set: function (val) {
this._titleValue = val;
this.dispatchEvent("title");
}
}
};
Since WinJS class define can only specify one constructor function (as far as I understand it), you may use the static members to define a factory function that will take the serialized data as a parameter. This factory methdod will actually create a new instance and will set the values one by one and return the new object.
It as some advantages like the fact that you can actually manage the data structure changes over the time you enhance the app...
The drawback is that you cannot write new MySuperClass() all the time...
...
// let's suppose we already called JSON.parse(data);
create: function(serializedData) {
var newObj = new MySuperClass();
newObj.name = serializedData.name || "";
newObj.color = serializedData.color || "";
return newObj;
}
Then you will call somewhere else in the app :
var myInstance = MySuperClass.create(serializedDataFromfile);
You should just be able to call JSON.parse after pulling it out of local storage:
var myObject2;
myObject2 = JSON.parse(localStorage["mySeriazliedObject"];
should a getter of a private property return a reference to the property or the value of the property (or a clone if the property is an object).
If the property has a primitive type (string, number, boolean) or a reference to an immutable object (String, Number), the answer is that you return the value/reference directly, since there's nothing the caller can do with it that will change your object's state.
If the property has a reference type to a mutable object (an array, an Object, a Date, lots and lots of other things), it depends on whether you want the caller to be able to change the properties on your object's copy of it. If you do, return the reference. If not, clone it.
For example, let's assume an object with a private array and some operations you can perform on that array:
var obj = (function() {
var o = {};
var theArray = [];
o.addItem = function(item) {
theArray.push(item);
};
o.getItemAt = function(index) {
return theArray[index];
};
return o;
})();
(Note that this is not meant to be a glorious example of object design. :-) )
Now you want to add a getArray operation. You can do that in two ways:
You can return a reference to the array:
o.getArray = function() {
return theArray;
};
...which means the caller can do all sorts of things to it (like remove items from it, an operation the object didn't previously support) that will change your object's state (because you've given them direct access to the formerly-private array).
Or you can return a clone of the array:
o.getArray = function() {
return theArray.slice(0);
};
...which means the caller can't do anything to the private array, they can only operate on the copy of it you gave them.
This depends whether the private property is immutable or not. If it's immutable, it can't be changed and there is no harm in returning it. If however it is mutable, then returning it will break the OOP principle of information hiding.
If it's a primitive immutable int/number, then returning the private property is fine since it achieves two things:
You hide the private property and provide an interface, and any changes to the implementation of the private property will not break the interface as easily
The returned object (in this case a value) can't be changed by the caller because it's a primitive type and is passed by value
If however, you return a mutable Array from a method and your language passes objects by reference, then you must accept the fact that the caller may decide to change this internal object - which could very easily lead to your internal code breaking.
For these reasons, if you plan to return a copy to a mutable object, return a copy and not the underlying object itself.
Generally wherever the property is to be used should not be able to change the property value. This satisfies the important principle of the OOP i.e Encapsulation.