If I have an object that I want to "inherit" methods from a "super object" to ensure consitency. They will be intermingling variables. REVISED
ParentObj = function()
{
var self = this;
this.interval = null
this.name = "";
this.timeout = 1000;
this.stop = function()
{
clearInterval(self.interval);
};
this.start = function()
{
self.log("Starting up");
setTimeout(function(){
self.getData(true);
self.interval = setInterval(function(){
self.getData();
}, self.timeout)
}, 1000);
};
this.log = function(msg)
{
require("sys").log(self.name + ": " + msg);
};
this.getData = function(override)
{
if(override || self.interval)
{
/**
* Allow
*/
self.log(new Date());
}
else
{
self.log("Unable to override and no interval");
}
}
}
ChildObj = function()
{
var self = this;
this.name = "Child";
this.timeout = 500;
this.start();
setTimeout(function(){
self.stop();
}, 2000);
}
ChildObj.prototype = new ParentObj();
var c = new ChildObj();
This doesn't seem to work correctly, specifically it not seeing the self.interval and is unable to clear it.
I'm open to other JavaScript inheritance methods, if they exist, but I really need to start encapsulating stuff off into the parent. There are three or four functions that are identical, but being changed at times and this means I have to run through a dozen files to make the change, rather then simply altering the parent.
Working through some of the suggestions I've tried to more clearly define what sort of functionality I'm going for. Ideally all the "children" will have a couple of unique settings (name, interval, config settings) and a getData() method while the parent manages starting, stopping, logging, and anything else.
'Clone' an object by making the object the prototype of a throwaway function and calling that function with 'new'.
Clone the parent constructor's prototype, and set the result as the prototype of the child class.
...
/**
* Extend a constructor with a subtype
* #param {Function} superCtor Constructor of supertype
* #param {Function} subCtor Constructor of subtype
* #return {Function} Constructor of subtype
*/
var extend = (function(){
return function (superCtor, subCtor) {
var oldProto=subCtor.prototype;
subCtor.prototype=clone(superCtor.prototype);
return merge(subCtor.prototype, oldProto).constructor=subCtor;
}
function Clone(){}
/**
* Clone an object
* #param {Object} obj Object to clone
* #return {Object} Cloned object
*/
function clone (obj) { Clone.prototype=obj; return new Clone() }
/**
* Merge two objects
* #param {Object} dst Destination object
* #param {Object} src Source object
* #return {Object} Destination object
*/
function merge (dst, src) {
for (var p in src) if (src.hasOwnProperty(p)) dst[p]=src[p];
return dst;
}
}());
Using this inheritance method, you can only mingle variables "upstream." Your child object will be able to see the public properties of its prototype, but the prototype cannot see the properties of its children. It must be self-contained.
(EDIT: I just noticed you're also using "self" without declaring it in sobj.)
sobj = function()
{
var self = this;
self.close = function()
{
clearInterval(self.interval);
}
self.interval = null;
}
cobj = function()
{
var self = this;
self.interval = setInterval(function(){ /* Do something */}, 1000);
}
// set cobj.prototype - see explanation below
For how to properly set the prototype (and an in-depth look at how inheritance works in JS), I refer you to Douglas Crockford's book JavaScript: The Good Parts.
He has actually posted how to properly set the prototype on his site. Be sure to use the version that does not touch Object.prototype, as many scripts (jQuery for starters) will break if you change it.
First thing, I don't think that var this.interval is okay. var keyword is used to define a variable, but in your case you are referencing an object.
Second, if you want to declare "interval" as a method of your cobj, you have to wrap the body of the function in a function.
So, this way it works for me:
var sobj = function()
{
this.close = function()
{
clearInterval(this.interval);
}
}
var cobj = function()
{
this.initInterval = function(){ this.intervalid = setInterval(function(){ alert("test")}, 5000)};
this.intervalid = null;
}
cobj.prototype = new sobj();
var inst = new cobj();
inst.initInterval();
After I've defined the constructor functions, I create an actual instance of a "cobj" object and then call "initInterval" to initialize the "setInterval".
UPD: updated the code per #MooGoo's comment.
Related
I'm not very well aquainted with javascript inheritance, and I'm trying to make one object inherit from another, and define its own methods:
function Foo() {}
Foo.prototype = {
getColor: function () {return this.color;},
};
function FooB() {}
FooB.prototype = new Foo();
FooB.prototype = {
/* other methods here */
};
var x = new FooB().getColor();
However, the second one overwrites the first one(FooB.prototype = new Foo() is cancelled out). Is there any way to fix this problem, or am I going in the wrong direction?
Thanks in advance, sorry for any bad terminology.
Each object can only have one prototype, so if you want to add to the prototype after inheriting (copying) it, you have to expand it instead of assigning a new prototype. Example:
function Foo() {}
Foo.prototype = {
x: function(){ alert('x'); },
y: function(){ alert('y'); }
};
function Foo2() {}
Foo2.prototype = new Foo();
Foo2.prototype.z = function() { alert('z'); };
var a = new Foo();
a.x();
a.y();
var b = new Foo2();
b.x();
b.y();
b.z();
One solution would be:
function FooB() {}
var p = new Foo();
p.methodA = function(){...}
p.methodB = function(){...}
p.methodC = function(){...}
...
FooB.prototype = p;
Update: Regarding expanding with an existing object. You can always copy the existing properties of one object to another one:
FooB.prototype = new Foo();
var proto = {
/*...*/
};
for(var prop in proto) {
FooB.prototype[prop] = proto[prop];
}
As long as proto is a "plain" object (i.e. that does not inherit from another object) it is fine. Otherwise you might want to add if(proto.hasOwnProperty(prop)) to only add non-inherited properties.
You can use an extend function which copies the new members to the prototype object.
function FooB() {}
FooB.prototype = new FooA();
extend(FooB.prototype, {
/* other methods here */
});
extend
/**
* Copies members from an object to another object.
* #param {Object} target the object to be copied onto
* #param {Object} source the object to copy from
* #param {Boolean} deep whether the copy is deep or shallow
*/
function extend(target, source, deep) {
for (var i in source) {
if (deep || Object.hasOwnProperty.call(source, i)) {
target[i] = source[i];
}
}
return target;
}
Having this code:
function Element() {
this.name = "yay";
}
Element.prototype.extend = function(object) {
if (object instanceof Object) {
for (var n in object) {
if (object.hasOwnProperty(n)) {
this[n] = object[n];
}
}
}
};
var el = new Element();
el.extend({
update: function() {
console.log(this.name);
}
});
I want WebStorm to know that update() this is an instance of Element, but I don't really know how to do it.
The maximum I've reached is this:
el.extend({
/**
* #this Element
*/
update: function() {
console.log(this.name);
}
});
But I don't want to do that in every extend().
Also found this:
/**
* #typedef {Object} FunctionExtend
*/
/**
* #param {FunctionExtend} object
*/
Element.prototype.extend = function(object) {
[...]
But I'm stuck in:
How to declare FunctionExtend to have undefined number of parameters.
How to tell that each #parameter will be a callback without knowing the parameter name.
How to tell what is the #this of the callbacks.
Extending prototypes to begin with is generally a Bad Idea™, and it does not play well with write-time documentation tools like JSDoc.
You will probably have no choice but to document every function individually.
I'm trying to pass a parameter from the child module to the parent module constructor but for some reasons the parameter is not passed to the parent.
This is the child module:
var Child = (function()
{
/**
* #constructor
*/
var Child = function(offer)
{
_Parent.call(this, offer);
};
/**
* Prototype.
*/
Child.prototype = Object.create(_Parent.prototype);
Child.prototype.construct = Child;
return Child;
}());
And the following is the parent:
var _Parent = (function()
{
/**
* Contains the offer data.
*
* #type {{}}
*/
var offerData = {};
/**
* #construct
*/
var _Parent = function(offer)
{
offerData = offer;
};
/**
* Get the offer price.
*
* #param offering Index of the offering of which the price should be returned.
*/
var getPrice = function(offering)
{
if(typeof offering == 'undefined')
{
offering = 0;
}
return offerData[offering]['Prices']['PriceRow']['TotalPriceInclVAT'];
};
/**
* Prototype.
*/
_Parent.prototype = {
construct : _Parent,
getPrice : getPrice
};
return _Parent;
}());
I'm trying the getPrice() function on the child like this:
var child = new Child(offers);
child.getPrice();
but I receive always Uncaught TypeError: Cannot read property 'undefined' of undefined inside the getPrice function whenever i try to return the data.
Are you sure offers isn't undefined?
Another problem is that offerData isn't an instance property but a variable inside a closure where the Parent constructor is defined. When you create a new instance, it will override offerData in the closure, wiping out whatever was defined by the previous instantiation.
It's the same as doing this:
var foo = {};
function Parent(bar){
foo = bar;
}
Parent.prototype.getFoo = function(){
return foo;
}
function Child(bar){
Parent.call(this, bar);
}
Child.prototype = Object.create(Parent.prototype);
var hello = new Parent('Hello');
console.log(hello.getFoo()); // Hello
var world = new Child('World');
console.log(world.getFoo()); // World
console.log(hello.getFoo()); // World... wut???
This can be remedied by putting offerData as an instance property so it attaches per instance. You can always resort to pseudo-privates (prefix _ by convention) if you want to keep the concept of privacy.
var _Parent = function(offer){
this._offerData = offer;
};
It is because you defined _Parent only after you defined Child.
You need to first define _Parent and then the Child because the Child uses the parent in the line
Child.prototype = Object.create(_Parent.prototype)
I tested it, and it worked.
I was thinking that having a function with variables and methods would be able to allow the subfunctions to reference the variables. Maybe I am doing it wrong, and would like some advice on how to properly fomat this stuff.
function somefunction(callback) {
var x,y,z;
var timervar = setInterval(function() {
//...
callback().always(function() {
x++;
});
//...
}, 1);
}
How would i properly relate the X?
Edit:
I am doing some iteration within a while loop. x,y,z are variables which are to store counter information. I was more or less incremementing or decremementing a variable when callback finished execution.
The reason why it isnt calling more callback() is because it is in while loop. WHich is fine and dandy as it is related to the X value. It seems that after a certain point, it exits the scope of the while loop and waits for .always() to be fired off so it would then be able to resume the while loop. The while loop is set within the timer, so it checks every 10ms if it is ready to keep looking.
Final Edit: always wasnt firing because i forgot the return in callback() so it was never recognized as finished. ._.
Another way is to make self contained module:
somefunction = (function() {
var x,y,z;
return {
callback: function(){
return x++;
}
}
});
You can explore a great documentation on JavaScript Design Patterns on http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
Try something like
var SomeObj = {
x: 0,
myFunc : function(){
SomeObj.x++;
}
}
Try this:
function createObject(o) {
function F() {}
F.prototype = o;
return new F();
}
Taken from Prototypal Inheritance: http://javascript.crockford.com/prototypal.html
var SomeObj = {
x: 0,
myFunc : function(){
SomeObj.x++;
}
}
var newObj = createObject(SomeObj);
Maybe this post would help? https://stackoverflow.com/a/3075818/566012
I used the following implementation of inheritance in JS
/**
* inheritance
*
* #author Kevin Lindsey
* #version 1.0
*
* copyright 2006, Kevin Lindsey
*
*/
// namespace placeholder
TWE = {};
/**
* A function used to extend one class with another
*
* #param {Object} subClass
* The inheriting class, or subclass
* #param {Object} baseClass
* The class from which to inherit
*/
TWE.extend = function(subClass, baseClass) {
function inheritance() { }
inheritance.prototype = baseClass.prototype;
subClass.prototype = new inheritance();
subClass.prototype.constructor = subClass;
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
}
Then you could do something like:
function myBaseClass() {
this._datamember1 = ....;
//more data members
}
function mySubClass() {
mySubClass.baseConstructor.call(this);
//list additional data members here
}
TWE.extend(mySubClass, myBaseClass);
see more here
http://www.kevlindev.com/tutorials/javascript/inheritance/index.htm
I would say that you can assign
var me = this;
Then in your code you can use me.x, me.y etc.
I was experimenting with some examples and came across a problem that if we want to add a function to a prototype it will not be able to access the private members of the constructor. I came across this solution. This seems to be a nice hack.
I tried out some other ways and I got the following:
var Restaurant = function()
{
var myPrivateVar;
var private_stuff = function() // Only visible inside Restaurant()
{
return "I can set this here!";
}
Restaurant.prototype.use_restroom = function() // use_restroom is visible to all
{
private_stuff();
}
Restaurant.prototype.buy_food = function() // buy_food is visible to all
{
return private_stuff();
}
}
var restaurant = new Restaurant();
restaurant.buy_food(); // this would work
restaurant.private_stuff(); // this won't
The solution seems weird because we are adding to the prototype within the constructor function. (I haven't seen much of this). It works on firefox 5 and chrome at least. Is there something wrong with it?
What you're doing is redefining those methods on the prototype every time you make a new restaurant object. The more sane way to do that would be to define them on this, which is the new object being constructed in a constructor:
var Restaurant = function()
{
var myPrivateVar;
var private_stuff = function() // Only visible inside Restaurant()
{
return "I can set this here!";
}
this.use_restroom = function() // use_restroom is visible to all
{
private_stuff();
}
this.buy_food = function() // buy_food is visible to all
{
return private_stuff();
}
}
You could just do it like this though, and not use new:
var RestaurantMaker = function () {
var myPrivateVar;
var private_stuff = function() {
return "I can set this here!";
}
return {
use_restroom: function () {
private_stuff();
},
buy_food: function () {
return private_stuff();
}
};
}
and then just do:
var restaurant = RestaurantMaker();
This is called the revealing module pattern. The downside is that each new object gets a copy of all the functions, which also happens if you add methods to this in your constructor.
A very small alternative version of the revealing module pattern (which I think reads a bit better) looks like this:
var RestaurantMaker = function () {
var myPrivateVar;
function private_stuff() {
return "I can set this here!";
}
function use_restroom() {
private_stuff();
}
function buy_food() {
return private_stuff();
}
return {
use_restroom: use_restroom,
buy_food: buy_food
};
}
Then, if you want to change whether a function is private or not, it's just a matter of adding or removing it from the returned object.
I didn't actually test this, but I think all the objects would access to the last instantiated object's private properties.
On each instantiation you're binding the prototype methods (shared across all instances) to the private variables of the object being instantiated :)
Honestly, it doesn't make a lot of sense to me. Sure, you can have calls to your private functions this way, but it doesn't solve the initial problem - that is, you still need to add methods inside the constructor.
If you want to add methods to the class outside the constructor, you can use closures to keep constructors clean:
// Creating a closure inside a self-calling function
var Restaurant = (function() {
// Only visible inside this closure
var myPrivateVar;
var private_stuff = function() {
return "I can set this here!";
}
var Restaurant = function() {};
// use_restroom is visible to all
Restaurant.prototype.use_restroom = function() {
private_stuff();
};
// buy_food is visible to all
Restaurant.prototype.buy_food = function() {
return private_stuff();
};
// We give back the Restaurant-constructor to the people
return Restaurant;
})();
var restaurant = new Restaurant();
restaurant.buy_food(); // this would work
restaurant.private_stuff(); // this won't
We take a different approach. We do use closures sometimes, but only when you need to manage state at the class level. We use namespaces to manage scope. For a simple class with prototype methods, we just do this:
/**
* #namespace
*/
var chain = {};
(function () {
/**
* The constructor is used to manage private data
* #constructor
*/
chain.Restaurant = function () {
// Only visible inside this constructor
var inventory = { };
/**
* add an item with a count to the inventory
* This is a privileged function.
* #param {String} item The identifier for the item you are adding
* #param {String} count The count you are adding for the item.
*/
this.addInventory = function (item, count) {
if (count < 0) {
// throw an error
}
var current = this.getInventory(item);
inventory[item] = current + count;
}
// privileged function
this.getInventory = function (item) {
if (inventory.hasOwnProperty(item)) {
return inventory[item];
}
return 0;
}
// privileged function
this.removeInventory = function (item, count) {
throwIfNegative(count);
if (this.getInventory(item) < count) {
throw new Error("Inventory Unavailable");
}
inventory[item] -= count;
}
// private function, only visible to the privileged functions
function throwIfNegative (value) {
if (value < 0) {
throw new Error("Negative Inventory Is Not Valid");
}
}
}
// member/prototype method
chain.Restaurant.prototype.sellInventory = function (item, count) {
var availabe = this.getInventory(item);
var sellCount = Math.min(available, count, 0);
if (sellCount > 0) {
// do this conditionally if there are implications to invoking the functions
this.removeInventory(sellCount);
sellItem(item, sellCount);
}
return sellCount;
}
// member/prototype method
chain.Restaurant.prototype.hasInventory = function (item, count) {
return this.getInventory(item) >= count;
}
// namespace method
chain.soldQuantity = function (item) {
if (!itemsSold.hasOwnProperty(item)) {
return 0;
}
return itemsSold[item];
}
// functions defined in this closure can see this
var itemsSold = { };
// all functions defined in this closure can call this
function sellItem (item, quantity) {
if (!itemsSold.hasOwnProperty(item)) {
itemsSold[item] = 0;
}
itemsSold[item] += quantity;
}
})();