Use the following simple example:
var MyObject = {
name: '',
object_id: '',
awesomeFunction: function() { console.log('awesome'); }
};
Now, this is fine until I think about prototypal inheritance. Say i now want to inherit from this object:
var child_object = Object.create(MyObject);
This instantly causes problems because the child object has not specified the name and object_id properties which will therefore be taken from the parent object (prototype). And there is no native way to enforce that child objects are created with their own versions of these, right?
Is this understanding correct?
If so, am i thinking about inheritance in javascript incorrectly?
Should objects be treated as containers for functions instead?
And there is no native way to enforce that child objects are created with their own versions of these, right?
If you want all the instances to have those attributes, by default, then you should not inherit but construct them. The normal way to do this would be
function Parent(name, id) {
this.name = name;
this.id = id;
}
function Child(name, id) {
Parent.call(this, name, id);
}
Now, when you create an instance of Child, they will have their own version of name and id. Also, you can assign values to them while creating them itself.
Related
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.
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'm coming at this from the OOP world and trying to wrap my head around "classes" in Javascript. I'd like to be able to create a class with properties but not have to assign values to them right away. Something like the following:
var MyObject = function(id) {
this.id = id;
// Create the property so it is present on all instances but don't require it to be assigned to right away.
this.friendId;
}
MyObject.prototype = {
constructor: MyObject
// Etc...
}
Is there a way to do this or am I just not getting how it works in Javascript?
Simply omit the property from the declaration:
function MyObject(id)
{
this.id = id;
}
var obj = new MyObject(123);
console.log(obj.friendId); // undefined
Alternatively, explicitly set it to null in the constructor.
This Mozilla Developer Network article is a good read.
It compares Class based and Prototype based languages and provides side by side codes samples in Java and in JavaScript.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
Quoting from the article.
Constructor function or prototype specifies an initial set of properties. Can add or remove properties dynamically to individual objects or to the entire set of objects.
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've created an ashx page which is going to serve me an XML document full of basic user information. I'm not sure which is the best way to go about creating and populating my custom javascript object. I've seen them created in two ways:
function User() {
this.Id;
this.FirstName;
this.LastName;
this.Title;
}
and
var User2 = {
Id: null,
FirstName: null,
LastName: null,
Title: null
}
I could populate each of these by doing something like:
//first object
User.Id = 1
//second object
User2.FirstName = 'John'
Is one method of creating the object better than the other?
Edit: A year and a half later I saw that this question got the popular badge, so I just wanted to mention that today I am using Crockford's module pattern.
You cannot access the first object's properties without instantiation, i.e. using the new keyword:
var myUser = new User() ;
document.write(myUser.id) ;
The second object is an object literal which is accessible without instantiation as it is already instantiated when parsed.
The difference comes into play if you want use prototypical inheritance to create a new object on basis of the old one. Writing an object literal is probably easier to understand and the more appropriate pattern if you have a rather compact code base. However, prototyping comes in handy if you want to create a new object by augmenting an existing object with another object without having to rewrite the object getting augmented:
ipUser.prototype = User ;
ipUser.ip = "128.0.0.1" ;
In your case this difference might not seem striking, but you have to imagine how much redundant code you would get if you would create another object literal for every meager addition to the original object.
Look into the Mozilla Developer Center's page on JavaScript Objects if you have additional questions, it's outlined pretty well: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Object .
Hth
You don't have to create an object with empty values first. JavaScript doesn't need place holders and can add properties and methods dynamically at any time. That is, this would suffice as well:
var User2 = {};
User2.Id = 1;
User2.FirstName = 'John';
//...Etc.
If you're just concerned about storing data I'd use this form (the object literal, ie. your second method).
Update: You could also make things a bit easier and create a function that creates user objects for you:
function createUser(id, firstname, lastname, title) {
return {
Id: id,
FirstName: firstname,
LastName: lastname,
Title: title
};
}
var User2 = createUser(1, 'John', 'Smith', 'Manager');
The first is a typical object, known from OOP. You can add functions to act on the attributes like this (assuming there is a function getFullName):
var u = new User();
u.getFullName();
The second one is just an associative array, in which strings are mapped to values.
In JavaScript the boundary between the two is not as strict as in ohter programming languages.