I'm using JSON.stringify and JSON.parse to store and retrieve objects from localStorage. However, it appears that JSON.stringify strips out the instance functions from the object. Thus, after JSON.parse, I can no longer call myObject.doSomething(). I know that I can attach this function manually: myObject.doSomething = MyClass.prototype.myFunction, but that'll be troublesome if this action is repeated many times in the web app. How do people normally do this in JavaScript?
JSON obviously does not hold onto the functions themselves is only stores simple typed variables. The way I have addressed this in the pass is to be a restore method in my class and simply call that method with the data from JSON so as to re-populate the class with the data that belongs in it.
I have done this extensively with the Value Object ( VO ) design pattern in my code base and it has worked quite well for me. Just a word of a caution though, Ie7/Ie8 are not terribly friendly with this approach if you try to communicate across windows. As I recall I think it is IE7 that does not return the right "typeof" for some properties so I ran into a whole bunch of challenges in my restore when cross-window communication was involved.
Related
There appear to be a number of different ways how to access properties of a Sencha (Touch) model. However, I don't seem to be able to find proper documentation of which is the "correct" way of doing it.
Model creation
var model = Ext.create('MyApp.model.MyModel', {
name: value,
foo: bar,
...
})
Property access
model.get('name') or model.set('name', newValue)
model.data.name or model.data.name = newValue
model.raw.name seems to always return a string no matter what the data type in the model definition is?
Let's sort this all out:
get and set methods are the intended accessors for model field values.
model.data is the object that stores the client side model value, that is that have been converted from the data received from the server proxy using the fields configuration (type, convert method, etc.).
model.raw is the raw data that was received from the server proxy, before it was converted to client side application domain model values. You should avoid using it, or you will tie yourself to your proxy/server.
model['name']: as you've said, it doesn't work. Don't hope for it to come back (I don't even really understand that it worked at one point).
Now, which one should you use? Clearly, the last two ones are already out of the match.
The model.data object should give you the expected result in most cases (see bellow), and should give you a marginal performance gain other calling a function.
However, IMO you should always prefer to use the getters and setters, for two reasons.
First, it might happen that someone in your team (or you from the past) decides that the getter/setter is a good point to add some custom logic. In this case, bypassing the accessor by using the data object directly will also bypass this logic, and yield unpredictable result.
Secondly, getters and setters make it really easier to debug some situations, by making it easy to know from where modifications of the model values are coming. I mean, if one day you were to ask yourself "f**k, why is my model field value changing to this??". If all the code uses the getters, you'll just have to put a breakpoint in there, and you'll catch the culprit hand in bag. On the other hand, if the incriminated code uses the data object directly, you'll be stuck to do a whole project search for... You can't tell exactly what... data.name =? data['name'] =? name:? etc.
Now that I think about it, there is yet another reason. A deprecated one apparently. But the data object name used to be customizable using this persistenceProperty option. So, in some cases, the data object won't even be available, and code doing model.data.name instead of model[model.persistenceProperty].name would crash, plain and simple.
Short answer: use the accessors.
I am using the new(ish) chrome.storage.sync API for a chrome extension and the when saving objects, it completely ignores functions.
This means that when I retrieve objects from storage, I have the data in the object, but no functions.
Is there a way to reconnect the object's data to its functions?
Note: I'm not doing anything weird in the functions (like adding variables to it or changing its closure)
You basically need to run your object through a constructor function after it comes out the data storage thing.
I don't think there is a way to save functions persistently.
You could save an object with like.. self.fns=['fn1','fn2']; and on reload, add the functions back based on that.
But you should probably change your design if you are dynamically adding functions to things and need to save them that way.
I can't use JSON.Stringify because the document object goes many many levels deep. I tried the function over at: http://www.davidpirek.com/blog/object-to-string-how-to-deserialize-json but I get an error _o.hasOwnProperty is not a function. Anyone have any advice or tips?
You can not serialize 'document' to JSON string using JSON.stringify, since it contains circular references. One way to deal with circular references is to implement your own stringify method, which keeps tracks of the circular references and excludes those. (see this answer: How to solve circular reference in json serializer caused by hibernate bidirectional mapping?)
As already said in the comments, do you really need to serialize the document object?
I've been working with a similar kind of project (time to advertise: http://hannotaatio.futurice.com) and we do not serialize document object. Instead, relevant information from document object is stored using JavaScript. The code is on Github so feel free to check it out.
Apparently one way to go is simply to use jQuery. I don't love it, but it'll do for now.
I'm trying to pass an object to a web worker through the postMessage function.
This object is a square that has a couple of functions to draw himself on a canvas and some other things. The web worker must return an array of this objects.
The problem is that when I call the postMessage function with this object, I get an this error:
Uncaught Error: DATA_CLONE_ERR: DOM Exception 25
I get this both sending the object to the worker and the other way around.
I think the error is because javascript must serialize the object, but can't do it because the object has functions built-in.
Does anyone ever had a similar problem? Do you know some workarround to this?
Thanks in advance.
There are a few reasons why the error that you mention could have been thrown, the reasons are listed here.
When sending objects to web workers, the object is serialized, and later deserialized in the web worker if the object is a serializable object.
This means that the methods for the objects you send to your web worker are not something that can be passed to the web worker (causing the error that you have run into), and you will need to provide the necessary methods/functions to the objects on the web worker's side of the environment, and make sure they are not part of the object that is passed to the web worker(s).
As you suspected objects with functions cannot be posted. The same goes for objects with recursive references, but this has changed in some browsers lately. Instead of risking doing manual and costly redundant serialization for every post you can perform a test at the beginning of your script to determine which functions to use for sending/receiving data.
I've had the same problem and solved it by moving almost all code into the worker and just keeping a renderer (wrapping the 2d context renderer) in the main thread. In the worker I serialize the different draw calls meant for the canvas into just numbers in an (typed) array. This array is then posted to the main thread.
So for instance when I want to draw an image I invoke the drawImage() method on my worker renderer instance in the worker. The call is translated into something like [13,1,50,40] which corresponds to the draw method enum, image unique id and its xy coordinates. Multiple calls are buffered and put in the same array. At the end of the update loop the array is posted to the main thread. The receiving main renderer instance parses the array and perform the appropriate draw calls.
I recently encountered this same problem when using web workers. Anything I passed to my worker kept all its properties but mysteriously lost all its methods.
You will have to define the methods in the web worker script itself. One workaround is to importScripts the class definition and manually set the __proto__ property of anything you receive. In my case I wanted to pass a grid object, defined in grid.js (yup, I was working on 2048), and did it like so:
importScripts('grid.js')
onMessage = function(e) {
e.data.grid.__proto__ = Grid.prototype;
...
}
When you pass data to a web worker, a copy of the data is made with the structured clone algorithm. It is specified in HTML5 (see § 2.9: Safe passing of structured data).
MDN has an overview of supported types. As functions are not supported, trying to clone objects containing functions will therefore throw a DATA_CLONE_ERR exception.
What to do if you have an object with functions?
If the functions are not relevant, try to create a new object that contains only the data that you want to transfer. As long as you use only supported types, send should work. Using JSON.stringify and JSON.parse can also be used as a workaround, as stringify ignores functions.
If the functions are relevant, there is no portable way. There are attempts to use a combination of toString and eval (e.g., used by the jsonfs library), but this will not work in all cases. For instances, it will break if your function is native code. Also closures are problematic.
The real problem with object and webworkers is with the methods of that objects. A object should not have methods just properties.
Ex:
var myClass = function(){
this.a = 5;
this.myMethod = function(){}
}
var notParseableObject = new myClass();
var myClass2 = function(){
this.a = 5;
}
var parseableObject = new myClass2();
The first wont work (with the mentioned error message) with postMessage and the second will work.
Some type of objects like ArrayBuffer and ImageBitmap which have the Transferable interface implementet and can be transfered without copy the Object.
Thats very usefull in Context of Canvas + Web worker cause you can save the time of copy the data between the threads.
take a look at the vkThread plugin
http://www.eslinstructor.net/vkthread/
it can pass function to a worker, including function with context ( object's method ). It can also pass functions with dependencies, anonymous functions and lambdas.
--Vadim
Another way of handling this (as I come across this question a decade later having needed to do it myself) is to define a static clone() function on your class that constructs a new object from (the properties of) an old one; then you can simply say
MyClass cloneObj = MyClass.clone(evt.data.myObj);
at the start of your worker to get a 'real' object of type MyClass that you can then call methods on from within your worker.
if you want to pass the object with methods you can stringify it and parse it at the receiving end.
postMessage(JSON.stringify(yourObject)
In the listener
this.worker.addEventListener('message', (event) => {
const currentChunk = JSON.parse(event.data);
});
I've started to wrap my functions inside of Objects, e.g.:
var Search = {
carSearch: function(color) {
},
peopleSearch: function(name) {
},
...
}
This helps a lot with readability, but I continue to have issues with reusabilty. To be more specific, the difficulty is in two areas:
Receiving parameters. A lot of times I will have a search screen with multiple input fields and a button that calls the javascript search function. I have to either put a bunch of code in the onclick of the button to retrieve and then martial the values from the input fields into the function call, or I have to hardcode the HTML input field names/IDs so that I can subsequently retrieve them with Javascript. The solution I've settled on for this is to pass the field names/IDs into the function, which it then uses to retrieve the values from the input fields. This is simple but really seems improper.
Returning values. The effect of most Javascript calls tends to be one in which some visual on the screen changes directly, or as a result of another action performed in the call. Reusability is toast when I put these screen-altering effects at the end of a function. For example, after a search is completed I need to display the results on the screen.
How do others handle these issues? Putting my thinking cap on leads me to believe that I need to have an page-specific layer of Javascript between each use in my application and the generic methods I create which are to be used application-wide. Using the previous example, I would have a search button whose onclick calls a myPageSpecificSearchFunction, in which the search field IDs/names are hardcoded, which marshals the parameters and calls the generic search function. The generic function would return data/objects/variables only, and would not directly read from or make any changes to the DOM. The page-specific search function would then receive this data back and alter the DOM appropriately.
Am I on the right path or is there a better pattern to handle the reuse of Javascript objects/methods?
Basic Pattern
In terms of your basic pattern, can I suggest modifying your structure to use the module pattern and named functions:
var Search = (function(){
var pubs = {};
pubs.carSearch = carSearch;
function carSearch(color) {
}
pubs.peopleSearch = peopleSearch;
function peopleSearch(name) {
}
return pubs;
})();
Yes, that looks more complicated, but that's partially because there's no helper function involved. Note that now, every function has a name (your previous functions were anonymous; the properties they were bound to had names, but the functions didn't, which has implications in terms of the display of the call stack in debuggers and such). Using the module pattern also gives you the ability to have completely private functions that only the functions within your Search object can access. (Just declare the functions within the big anonymous function and don't add them to pubs.) More on my rationale for that (with advantages and disadvantages, and why you can't combine the function declaration and property assignment) here.
Retrieving Parameters
One of the functions I really, really like from Prototype is the Form#serialize function, which walks through the form elements and builds a plain object with a property for each field based on the field's name. (Prototype's current – 1.6.1 – implementation has an issue where it doesn't preserve the order of the fields, but it's surprising how rarely that's a problem.) It sounds like you would be well-served by such a thing and they're not hard to build; then your business logic is dealing with objects with properties named according to what they're related to, and has no knowledge of the actual form itself.
Returning Values / Mixing UI and Logic
I tend to think of applications as objects and the connections and interactions between them. So I tend to create:
Objects representing the business model and such, irrespective of interface (although, of course, the business model is almost certainly partially driven by the interface). Those objects are defined in one place, but used both client- and server-side (yes, I use JavaScript server-side), and designed with serialization (via JSON, in my case) in mind so I can send them back and forth easily.
Objects server-side that know how to use those to update the underlying store (since I tend to work on projects with an underlying store), and
Objects client-side that know how to use that information to render to the UI.
(I know, hardly original!) I try to keep the store and rendering objects generic so they mostly work by looking at the public properties of the business objects (which is pretty much all of the properties; I don't use the patterns like Crockford's that let you really hide data, I find them too expensive). Pragmatism means sometimes the store or rendering objects just have to know what they're dealing with, specifically, but I do try to keep things generic where I can.
I started out using the module pattern, but then started doing everything in jQuery plugins. The plugins allow to pass page specific options.
Using jQuery would also let you rethink the way you identify your search terms and find their values. You might consider adding a class to every input, and use that class to avoid specifically naming each input.
Javascript is ridiculously flexible which means that your design is especially important as you can do things in many different ways. This is what probably makes Javascript feel less like lending itself to re-usability.
There are a few different notations for declaring your objects (functions/classes) and then namespacing them. It's important to understand these differences. As mentioned in a comment on here 'namespacing is a breeze' - and is a good place to start.
I wouldn't be able to go far enough in this reply and would only be paraphrasing, so I recommend buying these books:
Pro JavaScript Design Patterns
Pro Javascript techniques