recently, i came across a question of how jQuery acts as both a function, as well as an object. the thing that made it possible was that jQuery was actually a function (hence the $()) that was attached with properties (like $.each()).
now in my project, i would want to create a model (which technically is an array of stuff), add methods to it, and return it to a variable which will hold it. is it wise to do it like this? does it interfere with anything?
//i did it like this:
function createModel(name){
var model = internal.models[name] = [];
model.add = function(){..logic to add to the model..}
//more augmented methods here...
return model;
}
//create a model
var myModel = createModel('test');
//then i can do add
myModel.add('foo');
To add to that, I don't want to mess around with the actual Array prototype stuff. I'm doing this for the currently created array.
the model i'm making is not like Backbone.js' model which is a unit of data. It's more synonymous to Backbone.js' Collection, or a Database table.
Something in that style might do, also never start a model as an array, always take a function (constructor) and a proper object they are more flexible for that.
var model = function(data) {
this.data = data;
};
model.prototype.getData = function() {
return this.data;
};
var mod = new model({foo:'foo'});
mod.getData().foo
Related
Is their is anyway to make json object schema fixed so that whenever i will create new object it will show same fixed number of key. So that i can change the value for that key whenever required(As like setter and getter).
You're probably mixing json and javascript.
JSON is a data format for communication, it can be used to serailiaze javscript object to the server, but the server can serialize his own objects into JSON, wheter they come from nodeJS, Java, or whatever.
So let's assume you're talking about javascript, this is really easy let's say you want an object People with the field name, *firstname**, dateOfBirth. You can just create a class with his constructor like this :
// creating based fields
function People(){
this.name = null;
this.firstname = null;
this.dateOfBirth = null;
}
// instantiating objects :
var myPeople = new People();
But with that we can still do something like myPeople.foo = "bar". There is no way of preventing that in javascript. However you can make sure yourself that extrafield won't getserialized in JSON with something like this :
// adding method toJson to people
People.prototype.toJson = function(){
return JSON.stringify({name:this.name, firstname:this.firstname, dataOfBirth:this.dateOfBirth});
};
// using it
var myJsonString = myPeople.toJson();
So any extra field you could have need for some manipulation will be ignore on serializing to the serving. I advsied you that because you not only to filter you keys, but to translate some objects before serializing. For instance i never serialize Javascript Date object, i always take the Timestamp (from getTime() method).
I don't know if i understand your question clearly but here is what i came up with:
var schema = function(){
var a=0;
var b=2;
var getA = function(){
return a;
}
var setA = function(newValue){
a = newValue;
}
return {
getA:getA,
setA:setA
}
}
Then when you want a new instance you can do this.
var x = new schema();
x.setA(25);
x.getA();
I am probably not the first one doing this, but I can't find or figure out how to do it.
In my javascript I have an object with 5 properties, which are all object withg data properties and functions.
So it looks like this
function Maindata() {
var obj = this;
this.id = null;
this.profile= new Profile();
this.company= new Company();
//and more
this.getid = function(){
return obj.id;
};
}
and the profile and company object also has data and functions.
Now I get an object from the server, which is the same object, but only the data, and not the functions.
Now I want to project all of the properties of the retrieved object from the server to my JavaScript object.
I've read to use jQuery Extend, but that doesn't work for me, because it only preserves the functions on the root (Maindata) object, but not on the sub-objects.
How can I load all the data from the subobjects too?
Do I have to $extend the subobjects one by one, like this:
$.extend(true, maindata.profile, result.profile);
$.extend(true, maindata.company, result.company);
or is there another solution?
First of all, in general - you want to put all functionality on the prototype and all data on the object itself:
function Maindata() {
var obj = this;
this.id = null;
this.profile= new Profile();
this.company= new Company();
//and more
}
Maindata.prototype.getid = function() {
return this.id;
};
The prototype is assigned to every object created with Maindata as a constructor and it is shared across all Maindata instances. So it is likely more efficient and easier to reason about. It's kind of like classes in other languages.
This means you can do:
// creates an object with the given prototype without running the constructor
var o = Object.create(Maindata.prototype);
$.extend(o, result); // copy data over
// Object.assign(o, result); // with ES2015 assign syntax.
If your object is nested - then you need to do this in a nested way for subproperties. You can't get types for free since they are not encoded in the JSON. You can implement a custom serializer that does this automatically for you - some libraries like Backbone do this for you but IMO they do a pretty bad job and doing this yourself is pretty straightforward.
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 left scratching my head here. I am pretty new with both JSON and Javascript so I am wondering how I would go about this.
Say I have an object:
MyObject.prototype = {
// different methods and properties
_randomMethod: function MyObject_randomMethod() {
MyObject.myArray = [];
},
};
How do I declare an array property for my object (like above: MyObject.myArray = [];) and have it available throughout the object so I can access it in other methods.
Maybe this has already been covered and I am just not using the right terminology but if someone could help me out, I'd appreciate it since I can't figure it out myself.
Just so its clear, I want to declare this array property dynamically within a method like the example above and then be able to use it in other methods within this same object with the 'this' reference or something similar.
Use this to refer to the current instance:
MyObject.prototype = {
// different methods and properties
_randomMethod: function MyObject_randomMethod() {
this.myArray = [];
},
};
http://jsfiddle.net/5jSe3/
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"];