How to create an object inside an object in Javascript? - javascript

I have a want to create a object Metrics within which I need to initialize various other objects such as StatsD.
I know how to create Metrics object in javascript.
function Metrics(params) {
// initialize params
}
Metrics.prototype.functionName = function() {
}
However I am confused is how to embed an object inside another object and access its methods ?
In java it would be easy:
class Metrics {
StatsD statsD;
}
new Metrics().statsD.increment("foobar");
How would I do the same in javascript ?

You'd do it in the same way as in Java:
function Metrics(params) {
this.statsd = new StatssD();
}
The only difference is that you don't have to declare the attribute with its type - just initialising the property in the constructor is enough.

Just set the property (statsd in this case) to a new object (new StatsD()):
function Metrics(params) {
//Initialize params
this.statsd = new StatsD();
}
You could also attach the StatsD to the prototype:
Metrics.prototype.statsd = StatsD();

Related

How can an object literal's property be assigned to the return value of one of its methods?

So I am making a game to practice using the mvc paradigm. I create an object literal for my model and want the functions it needs to generate values for its properties to be in the object itself. I have tried this with no success. I have tried using "this" when calling the function and not using it. Either way, I get a function not defined error from chrome. What can I do to fix this? Here's the relevant code:
var model = {
genPlayers: function() {
return tempPlayerArray;
},
playerArray: genPlayers()
}
You can't do that. 1. there is no function with the name genPlayers() only model.genPlayers() and 2. object properties can't be accessed during object initialization.
What you could do is:
var model = {
genPlayers: function() {
return tempPlayerArray;
},
playerArray: null
};
model.playerArray = model.genPlayers();
Or if model.genPlayers always only returns the tempPlayerArray you could do this:
var model = {
genPlayers: function() {
return tempPlayerArray;
},
playerArray: tempPlayerArray
};

How to make the variable available in the methods of the class?

I apologize for this question, just starting to learn Javascript.
I have 2 methods:
Manager.prototype.filters = function () {
var user = [];
...
Manager.prototype.filters_main = function () {
var user = [];
...
I need to make the property 'user' available to the 2 methods (filters, filters_main). So that they can use the shared variable (user).
How it is possible to write?
You have to understand the prototype-based inheritance here.
var Manager = function() {
this.user = [];
}
var manager = new Manager();
These lines will define a Manager constructor function and create a new object. When you call the new Manager(), what happens is:
a new, empty, object is created: {}.
the code inside the constructor will run with this new, empty, object being the value of this. So, it will set the user property of the new object ({}) to be an empty array.
the __proto__ property of the new object will be set to the value of Manager.prototype. So, this happens without you seeing: manager.__proto__ = Manager.prototype.
Then, you want to define new methods on your prototype objects, using the inheritance. Keep in mind that the prototype is a plain JS object. Not a constructor, but an object. So every object created from the Manager function will have its __proto__ property set to the same object.
Then, you start defining new methods on the prototype object, like the filters function. When you, later, call manager.filters(), it will first look up its own properties for the filters function and won't find it. So, then, it will go for its prototype properties, and there if will find it. manager will then run the filters function that was defined on the prototype, but using itself (manager) as the context, as the this inside the function.
So, to use your user property inside the filters function, all you have to do is:
Manager.prototype.filters = function () {
this.user = ...;
}
Manager.prototype.filters_main = function () {
this.user = ...;
}
and you'll be manipulating the same user property defined when the object was constructed.
Define the variable in your Manager definition:
function Manager() {
this.user = [];
}
And now you should be able to use it in your filter functions:
Manager.prototype.filters = function() {
// Use it:
if (this.user.indexOf(...) != -1) {
...
}
};
Then you can continue as normal:
var manager = new Manager();
manager.user = ["user1", "user2"];
var filters = manager.filters();
Add it to the body:
function Manager() {
this.user = [];
}
Manager.prototype.filters = function () {
alert(this.user)
}
var m = new Manager();
m.user = [11,22,33]
m.filters();

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 property inheritance

I'm trying to have a generic 'List' class, which will have:
Property: Items - which would be an array of 'what-ever'
Method: Add() - which would be abstract and implemented by the specific 'List' object
Method: Count() - which returns the number of 'items'
And then create sub-classes which will inherit from 'List':
// Class 'List'
function List(){
this.Items = new Array();
this.Add = function(){ alert('please implement in object') }
}
// Class CDList - which inherits from 'List'
function CDList(){
this.Add = function(Artist){
this.Items.push(Artist)
}
}
CDList.prototype = new List();
CDList.prototype.constructor = CDList;
// Create a new CDList object
var myDiscs = new CDList();
myDiscs.Add('Jackson');
myDiscs.Count() <-- this should be 1
// Create a second CDList object
var myDiscs2 = new CDList();
myDiscs2.Add('Walt');
myDiscs2.Add('Disney');
myDiscs2.Count() <-- this should be 2
...but this seems to create a shared 'Items' list for all 'CDList' instances. I need to somehow have a new inherited instance of the 'Items' list for each 'CDList' instance.
How can I do this?
*I'm using in this example the 'Items' list as an example. I'd like to be able to have in my sub-classes a new instance for any type of inherited property - not necessarily an Array object.
There is only one Array because you only create one. This array is attached to the prototype of "CDList" and therefore shared between all instances.
To solve this problem: don't attach it to the prototype, but to the instance. This can only be done at construction time:
// This is the constructor of the parent class!
function List() {
this.Items = new Array();
}
// Add methods to the prototype, not to the instance ("this")
List.prototype.Add = function() { alert('please implement in object'); };
// Constructor of the child
function CDList() {
List.call(this); // <-- "super();" equivalent = call the parent constructor
}
// "extends" equivalent = Set up the prototype chain
// Create a new, temporary function that has no other purpose than to create a
// new object which can be used as the prototype for "CDList". You don't want to
// call "new List();", because List is the constructor and should be called on
// construction time only. Linking the prototypes directly does not work either,
// since this would mean that overwriting a method in a child overwrites the
// method in the parents prototype = in all child classes.
var ctor = function() {};
ctor.prototype = List.prototype;
CDList.prototype = new ctor();
CDList.prototype.constructor = CDList;
// Overwrite actions
CDList.prototype.Add = function(Artist) {
this.Items.push(Artist);
};
Demo: http://jsfiddle.net/9xY2Y/1/
The general concept is: Stuff that each instance must have its own copy of (like the "Items" array in this case) must be created and attached to "this" (= the instance) at construction time, i.e. when doing new List() or new CDList(). Everything that can be shared across instances can be attached to the prototype. This essentially means that properties like the "Add" function are created exactly one time and are then used by all instances (what caused the original issue).
When linking prototypes, you must not directly link them (usually), e.g.:
CDList.prototype = List.prototype;
DVDList.prototype = List.prototype;
// Now add a new function to "CDList"
CDList.prototype.Foo = function() { alert('Hi'); };
Because the prototypes of the three functions "List", "CDList" and "DVDList" got directly linked to each other, they all point to one prototype object, and that is List.prototype. So, if you add something to CDList.prototype you actually add it to List.prototype - which also is the prototype of "DVDList".
var dvd = new DVDList();
dvd.Foo(); // <-- alerts "hi" (oops, that wasn't intended...)
What does the trick is to link the prototype to a new instance of the parent class:
CDList.prototype = new List();
This creates a new object of type "List()" with the special feature that the prototype of the function "List()" is linked to the new object, enabling you to call properties of the prototype directly on the object:
var l = new List();
alert( l.hasOwnProperty("Add") ); // <-- yields "false" - the object l has no
// property "Add"
l.Add("foo"); // <-- works, because the prototype of "List" has a property "Add"
However, remember that we intended to use the body of the function "List()" to create stuff like this array "Items" on a per-instance basis? It is the place where you put any "constructor" code, e.g.
function User(userId) {
$.getJSON('/user/' + userId, ...
}
function Admin() {}
Admin.prototype = new User( // ... now what?
One very clean solution is to use another function to create a prototype-object:
var ctor = function() {}; // <-- does nothing, so its super safe
// to do "new ctor();"
It is now okay to directly link the prototypes, because we will never add anything to ctor.prototype:
ctor.prototype = List.prototype;
If we then do:
CDList.prototype = new ctor();
the prototype of "CDList()" becomes a new object of type "ctor", that has no own properties but can be extended, e.g. by a new "Add" function:
CDList.prototype.Add = function() { /* CD specific code! */ };
However, if you do not add an "Add" property to this new prototype object, the prototype of "ctor()" kicks in - which is the prototype of "List()". And that's the desired behavior.
Also, the code in "List()" is now only executed whenever you do new List() or when you call it directly from another function (in a child class via List.call(this);).
Try this:
function CDList(){
List.call( this )
this.Add = function(Artist){
this.Items.push(Artist)
}
}
You need to call the superconstructor...
I like this article of the MDN network about JavaScript inheritance. I tried this method/technique and it works very fine in all browsers I tested (Chrome, Safari, Internet Explorer 8+, and Firefox)..

JavaScript : Create new object of a custom class based on an existing one (adding methods to it)

I use the iOS UI Automation framework to make sure my iPhone app rocks.
Everybody who uses this framework would tell you that it's great, but that it's lacking a lot of structure.
So I have to deal with instances of UIAWindow, which represent different screens of my app. To be more object-oriented, I'd like to have a specific class for each screen, so I could add specific methods, like
myScreen1.tapDoneButton();
var total = myScreen2.getNumberOfElements();
For the moment, I'm able to achieve this by passing the instances of UIAWindow to functions that will add the appropriate methods, like this :
function makeMainScreen(actualScreen)
{
actualScreen.constructor.prototype.getAddButton = function() {
return this.buttons()["add button"];
};
actualScreen.constructor.prototype.tapAddButton = function() {
this.getAddButton().tap();
};
// Add any desired method...
return actualScreen;
}
It works fine, I use it like this :
var mainScreen = makeMainScreen(app.mainWindow());
mainScreen.tapAddButton();
But that doesn't seem object-oriented enough, I would like to create real objects, using the new and this keywords, so I'd have a declaration like this :
function MainScreen(actualScreen){
// This line doesn't work : because 'this' is immutable
this = actualScreen;
this.tapAddButton = function(){
this.getAddButton().tap();
}
//...
}
And I'd use it like this :
var mainScreen = new MainScreen(app.mainWindow());
mainScreen.tapAddButton();
I thought I could save the actualScreen as a property of the object (Like in Grace Shao's answer below), and call all the methods on it, but I'd like keep the original UIAWindow methods.
Does anybody know how to do this?
Or perhaps what I'm trying to achieve doesn't make sense, in which case I'd be happy to know.
If I understand correctly, you could try the following:
function MainScreen(actualScreen){
this.screen = actualScreen;
}
MainScreen.prototype.tapAddButton = function () {
this.screen.getAddButton().tap();
};
MainScreen.prototype.getScreen = function () {
return this.screen;
};
//...
var mainScreen = new MainScreen(app.mainWindow());
mainScreen.tapAddButton();
You are correct that you cannot assign anything to this. You could also define the methods inside the constructor MainScreen, but they would be considered privileged members.
function MainScreen(actualScreen){
this.screen = actualScreen;
this.tapAddButton = function () {
this.screen.getAddButton().tap();
};
}
If you dont want them to be privileged members, it is better to define them outside the constructor. Otherwise, the members will be initialized over and over again everytime when you instantiate a new object.
Updated:
You could also wrappers for the methods of screen inside the constructor as below.
var prop;
for (prop in actualScreen) {
if (typeof actualScreen[prop] !== 'Function') {
continue;
}
this[prop] = function () {
return actualScreen[prop].apply(actualScreen, arguments);
};
}

Categories

Resources