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.
Related
I just cleared my mind on JavaScript objects and my question is really simple for most of the people here. I feel comfortable with the JavaScript object literal notation like:
var Obj = {
/**
* #type {string}
*/
name: '',
/**
* setName
* Set the `name` property.
*
* #param param
*/
set setName (param) {
this.name = param;
}
};
The only limit I found is that if I want to create two completely separate objects in the same page, with this notation I can't.
var a = Obj;
a.setName = "John";
var b = Obj;
b.setName = "Peter";
// OUTPUT
// a.name -> Peter
// b.name -> Peter
Set var whatever = Obj is just useless, 'cause it doesn't instantiate n separate objects and it just overwrites the code above. Using new keyword such as var a = new Obj doesn't work neither (probably I'm using it in the wrong way?). The solution I came up with is returning the object inside a function, like:
function Obj() {
return {
/**
* #type {string}
*/
name: '',
/**
* setName
* Set the `name` property.
*
* #param param
*/
set setName (param) {
this.name = param;
}
}
}
This way I can create two different objects and correctly access to their properties and methods:
var a = Obj();
a.setName = "John";
var b = Obj();
b.setName = "Peter";
// OUTPUT
// a.name -> John
// b.name -> Peter
So, my question are:
Is what I've done conceptually right?
Is there a more correct/efficient way to achieve it?
Your concept of a function that returns an Object instance is valid, but your implementation is very brittle because it is only set up to work with specific properties. Read on for more details on various ways to create instances and a more flexible way to return objects...
var a = Obj; doesn't create a new object. It just assigns a the memory address of the existing object Obj.
var myObj = {}; // Object instance is created and memory location is stored in myObj
var a = myObj; // No new object is created. a and myObj point to the same object
console.log("Are 'a' and 'myObj' both pointing to the same object?", a === myObj); // true
If you want to design a single object and then make more of that object, you need to be able to create "instances" of an object. You can't do that directly with an object literal:
var myObj = {
someProp:10
};
var myNewObj = new myObj(); // Fails because an object literal can't be instantiated
But, you can do it with the Object.create() method, which takes your Obj concept to fruition:
// Object instance is created and memory location is stored in myObj
var myObj = {
someProp: "default",
// "Methods" are just properties with functions as their value
someMethod: function(input){
// The || syntax that follows allows for a default value for the method
// if no argument is passed to the method.
this.name = input || "default";
}
};
// Create a new Object instance and set myObj as the prototype of the instance.
// This means that the new instance will inherit from that prototype:
var a = Object.create(myObj);
console.log(a.someProp); // "default";
a.someProp = "something specific";
a.someMethod("Test");
myObj.someMethod();
console.log(a.name, myObj.name); // "Test" "default"
console.log(a.someProp, myObj.someProp); // "something specific", "default"
Instances can be explicitly made with the new operator and a constructor function:
function foo(){
this.someProp = "something";
}
var a = new foo(); // Unique instance of foo
var b = new foo(); // Separate and distinct instance of foo
a.someProp = 10;
b.someProp = 20;
console.log(a.someProp, b.someProp); // 10 20
Or, the new operator and a class:
class foo{
constructor(val) {
this.someProp = val;
}
}
var a = new foo(10); // Unique instance of foo
var b = new foo(20); // Separate and distinct instance of foo
console.log(a.someProp, b.someProp); // 10 20
Have you tried with Object.create() ?
var b = { setName : "Mongo" };
a = Object.create(b);
a.setName = "John";
b.setName = "Peter";
console.log(a.setName);
console.log(b.setName);
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;
}
There must be something I don't understand about the JS object model.
From these resources:
Prototypes
Basic OOP in JS- Inheritance
Object.create()
I have gathered what I think, or thought, was an accurate mental representation of the object model. Here it is:
All objects have a property, which the docs refer to as [[Prototype]]. [[Prototype]] can be thought of as a reference to the object's parent. More accurately:
The reference to the [parent's] prototype object is copied to the
internal [[Prototype]] property of the new instance. (source 1)
You can get access to the [[Prototype]] property of the child with Object.getPrototypeOf(child) The value returned here will be a reference to the parent's prototype (not its internal [[Prototype]] property, but its actual prototype)
obj.prototype is different from the object's internal [[Prototype]] property. It acts like the blueprints used to make instances of this exact object, while its [[Prototype]] property points to the blueprints used to make instances of its parent.
Parent.prototype === Object.getPrototypeOf(child); //true
To elaborate:
If you add a function to child.prototype the function will be available to child and any of it's children.
If you add a function to parent.prototype, which is equivalent to adding a function to Object.getPrototypeOf(child), then the function will be available to parent and all of it's children, which includes child and all of its siblings.
You can use Object.create() to create a new object with whatever [[Protoype]] property you want. So you can use it as a way to implement inheritance. See source 2 for an example.
With this in mind, I wanted to get a working example of my own going. My plan was to create a parent 'class' and then make a child 'class' that inherited from it.
I wanted the child class to implement a method, which overloaded a method from the parent. The caveat is that I want the child's version of the method to call the parent's version of the method and then do some extra stuff.
Here is what I came up with, see below for the issues associated with it:
var Parent = function() {};
Parent.prototype.myF = function() {
console.log('derp');
};
function Child() {
Parent.call(this);
};
//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);
//need to explicitly set the constructor
Child.prototype.constructor = Child;
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
childInstance = new Child();
childInstance.myF();
It appears to be the case that when I attempt to overload Parent.myF(), while I am overloading it, I am actually modifying the original function at the same time. This appears to be the case because the logged results are:
'derp'
'did I derp??'
'did I derp??'
presumably the first occurance of 'did I derp??' is coming from a modified version of the parent's function, which I don't mean to do, then the second version is coming from the child's function.
Can anyone elaborate on why this is happening?
Great question, it took a bit of testing and researching to find it out.
Identifying the strange behaviour
I changed your code a little bit to find out which function is called when:
var Parent = function() {};
Parent.prototype.myF = function() {
console.log('derp');
};
function Child() {
Parent.call(this);
this.name = 'Test'; // this is a new test property
};
//make [[prototype]] of Child be a ref to Parent.prototype
Child.prototype = Object.create(Parent.prototype);
//need to explicitly set the constructor
Child.prototype.constructor = Child;
Child.prototype.myF = function() {
console.log(this); // here I want to find out the context, because you use it in the next line
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
childInstance = new Child();
childInstance.myF();
You can check out the JSFiddle and try it for yourself: http://jsfiddle.net/Lpxq78bs/
The crucial line in your code is this:
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF(); // this one
console.log("did I derp??");
};
After doing a console.log(this); to find out what this refers to, I saw that it changes between the first and the second output of did I derp??.
I got the following output:
Object { name: "Test" }
Object { constructor: Child(), myF: window.onload/Child.prototype.myF() }
"derp"
"did I derp??"
"did I derp??"
Interpreting the Output
Since I added a 'name' property to the Child constructor, it would only be around if I am looking at an instance of Child, not at its .prototype.
So the first line of the Output means that the current this context is indeed the childInstance. But the second one is neither the childInstance, nor the Parent.prototype:
Call (myF of childInstance): this refers to the childInstance. Object.getPrototypeOf(this).myF(); then looks for the [[Prototype]] of the childInstance, which is the Child.prototype, not the Parent.prototype.
Output: 'did I derp??'
Call (myF of Child.prototype): this refers to the Child.prototype, which is the childInstances [[Prototype]] Property. So the second call of Object.getPrototypeOf(this).myF(); finally returns the Parent.prototype (sort of). Output: 'did I derp??'
Call (myF of Parent.prototype instance created by Object.create): Finally, the myF on the parent is called. Output: 'derp'
Since your console.log("did I derp??") comes after the myF function call, the output is in reverse order. The following graphic illustrates how the code is traversed:
So your assumption about what Object.getPrototypeOf(this).myF(); refers to, was wrong.
Solution in ES5
By #LukeP:
https://jsfiddle.net/Lpxq78bs/28/
Alternative Solution in ES6
To avoid this confusion, and since you are working with a classical inheritance pattern, you could have a look at ES6 Classes. The following would be a rough example of what you are trying to do:
class Parent {
constructor() {
}
myF() {
console.log('derp');
}
}
class Child extends Parent {
constructor() {
super();
}
myF() {
super.myF();
console.log("did I derp??");
}
}
var childInstance = new Child();
childInstance.myF();
I hope this helps in understanding what happens.
Your code is working as expected , the output you are getting is because of Object.getPrototypeOf and can be explained by
Step 1 : When you cal childInstance.myF(); then it goes to below code where this refers to childInstance itself
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
then Object.getPrototypeOf returns childInstance.[[Prototype]] which is Child.prototype and again call myF method(leaving second line to printed later after the execution of the method) but next time this will reference to childInstance.[[Prototype]].
Step 2 : In this call this points to childInstance.[[Prototype]]( or Child.prototype object itself)
Child.prototype.myF = function() {
Object.getPrototypeOf(this).myF();
console.log("did I derp??");
};
Now Object.getPrototypeOf returns childInstance.[[Prototype]].[[Prototype]]( which is Child.prototype.[[Prototype]]) which is Parent.prototype and again call myF method but this time myF method will print derp because myF method of Parent.prototype is being called. After that, second line will print did i derp.
Step 3 : Then the function comes back to step 1 to execute second line which again prints did i derp
If you have to work with inheritance in ES5 I have made a wrapper that makes it easy to extend and call parent methods. No frameworks required.
fiddle to working code here: https://jsfiddle.net/wcrwLmrk/13/
Here is how the code works:
/* extend the base class to the new parent class and pass
an object with the new properties and methods */
var ParentClass = Class.extend(
{
// reset the constructor to the correct constructor
constructor: function()
{
},
callName: function(arg)
{
console.log('parent ' + arg);
}
});
/* extend the parent class to the new child class and pass
an object with the new properties and methods */
var ChildClass = ParentClass.extend(
{
// reset the constructor to the correct constructor
constructor: function()
{
ParentClass.call(this);
},
callName: function(arg)
{
// child method code
console.log('child ' + arg);
/* call parent method by passing the method name and any params */
this.super('callName', arg);
}
});
Now we can create a new child class that will
call the super class method:
var child = new ChildClass();
child.callName('name');
Here is the base class that needs to be included in the project:
var Class = function()
{
};
Class.prototype =
{
constructor: Class,
/* this is an alias for callParent. this will
allow child classes to call super methods.
#param (string) method name
#param [(mixed)] addasmany args as the super
method needs
#return (mixed) the super method return value */
super: function()
{
var parent = this.parent;
if(parent)
{
var args = [].slice.call(arguments),
// this will remove the first arg as the method
method = args.shift();
if(method)
{
var func = parent[method];
if(typeof func === 'function')
{
return func.apply(this, args);
}
}
}
return false;
}
};
/* this will return a new object and extend it if an object it supplied.
#param [(object)] object = the extending object
#return (object) this will return a new object with the
inherited object */
var createObject = function(object)
{
if(!Object.create)
{
var obj = function(){};
obj.prototype = object;
return new obj();
}
else
{
return Object.create(object);
}
};
/* this will extend an object and return the extedned
object or false.
#param (object) sourceObj = the original object
#param (object) targetObj = the target object */
var extendObject = function(sourceObj, targetObj)
{
if(typeof sourceObj !== 'undefined' && typeof targetObj !== 'undefined')
{
for(var property in sourceObj)
{
if(sourceObj.hasOwnProperty(property) && typeof targetObj[property] === 'undefined')
{
targetObj[property] = sourceObj[property];
}
}
return targetObj;
}
return false;
};
var extendClass = function(sourceClass, targetClass)
{
/* if we are using a class constructor function
we want to get the class prototype object */
var source = (typeof sourceClass === 'function')? sourceClass.prototype : sourceClass,
target = (typeof targetClass === 'function')? targetClass.prototype : targetClass;
if(typeof source === 'object' && typeof target === 'object')
{
/* we want to create a new object and add the source
prototype to the new object */
var obj = createObject(source);
/* we need to add any settings from the source that
are not on the prototype */
extendObject(source, obj);
/* we want to add any additional properties from the
target class to the new object */
for(var prop in target)
{
obj[prop] = target[prop];
}
return obj;
}
return false;
};
/* this will allow the classes to be extened.
#param (object) child = the child object to extend
#return (mixed) the new child prototype or false */
Class.extend = function(child)
{
if(!child)
{
return false;
}
var parent = this.prototype;
/* the child constructor must be set to set
the parent static methods on the child */
var constructor = child && child.constructor? child.constructor : false;
if(child.hasOwnProperty('constructor') === false)
{
constructor = function()
{
var args = arguments;
parent.constructor.apply(this, args);
};
}
constructor.prototype = extendClass(parent, child);
constructor.prototype.parent = parent;
/* this will add the static methods from the parent to
the child constructor. */
extendObject(this, constructor);
return constructor;
};
I'm creating two objects (Inherits), both inherit from Base.
The second object's property assignment overrides the value in the first object.
Any thoughts? How to make a proper inheritance so that Base class will contain common members for its inheritance descendants, but the descendants could assign values of their own without interfering each other.
var testParams1 = { title: "john" };
var testParams2 = { title: "mike" };
Function.prototype.inheritsFrom = function (baseClass)
{
this.prototype = new baseClass;
this.prototype.constructor = this;
this.prototype.base = baseClass.prototype;
return this;
};
function Base() {
this.viewModel = {};
this.viewModel.title = (function ()
{
var savedVal = "";
return function (newVal)
{
if (typeof (newVal) === "undefined")
{
return savedVal;
}
savedVal = newVal;
};
})();
}
function Inherits(params) {
this.viewModel.title(params.title);
}
Inherits.inheritsFrom(Base);
///// preparing code:
var testObj1 = new Inherits(testParams1);
var testObj2 = new Inherits(testParams2);
///// testing code:
equals(testObj1.viewModel.title(), testParams1.title, "first instance ok"); // returns "john"
equals(testObj2.viewModel.title(), testParams2.title, "second instance ok"); // also returns "john"
Problem(s)
The Base class constructor is called once and only once.
this.prototype = new baseClass;
Privileged methods will refer to the same this object across instances because those methods are created within the constructor (which was called only once).
Problem(s) based on a matter of opinion
You should try to avoid modifying native prototypes (ie. Function.prototype) if you plan on working alongside JavaScript that you do not own.
Solution
Call the constructor and parent constructor(s) for each new instance that is created.
Inherit the parent prototype chain (not a instance of a the parent class).
Maintain a 1:1 ratio of number of instances created to the number of calls the constructor(s) in the prototype chain.
Final solution to Max's problem
Please pay special attention to the inherits function and the ParentClass.call(this, title); line.
Constructors to look for are ParentClass and ChildClass
/**
* Allows a child constructor to safely inherit the parent constructors prototype chain.
* #type {Function}
* #param {!Function} childConstructor
* #param {!Function} parentConstructor
*/
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor
};
//////////////////////////////////////
/** #constructor */
function ParentClass(title) {
this.setTitle(title);
var randId_ = Math.random();
/** #return {number} */
this.getPrivlegedRandId = function()
{return randId_;};
};
/** #return {string} */
ParentClass.prototype.getTitle = function()
{return this.title_;};
/** #param {string} value */
ParentClass.prototype.setTitle = function(value)
{this.title_ = value;};
//////////////////////////////////////
/**
* #constructor
* #param {string} title
* #param {string} name
*/
ChildClass = function (name, title) {
ParentClass.call(this, title); // Call the parent class constructor with the required arguments
this.setName(name);
}
inherits(ChildClass, ParentClass); // Inherit the parent class prototype chain.
/** #return {string} */
ChildClass.prototype.getName = function()
{return this.name_;};
/** #param {string} value */
ChildClass.prototype.setName = function(value)
{this.name_ = value;};
Down the rabbit hole
For those who are curious why that works vs simply memorizing it the inherits function.
How properties are resolved using the prototype chain
When a property is not found at the instance level, JavaScript will try to resolve the missing property by searching through the instance constructors prototype chain. If the property is not found in the first prototype object, it will search the parent prototype object and so on all the way up to Object.prototype. If it can't find it within Object.prototype then an error will be thrown.
Calling the parent constructor from child constructor : Attempt #1
// Bad
var ChildConstructor = function(arg1, arg2, arg3){
var that = new ParentConstructor(this, arg1, arg2, arg3);
that.getArg1 = function(){return arg1};
return that;
}
Any varible that is created using new ChildConstructor will return an instance of ParentConstructor.
The ChildConstructor.prototype will be not be used.
Calling the parent constructor from child constructor : Attempt #2
// Good
var ChildConstructor = function(arg1, arg2, arg3){
ParentConstructor.call(this, arg1, arg2, arg3);
}
Now constructor and the parent constructor is called appropriately. However, only methods defined within the constructor(s) will exist. Properties on the parent prototypes will not be used because they have not yet been linked to the child constructors prototype.
Inheriting the parent prototype : Attempt #1
// Bad
ChildConstructor.prototype = new ParentConstructor();
The parent constructor will either be called only once or one too many times depending on whether or not ParentConstructor.call(this) is used.
Inheriting the parent prototype attempt #2
// Bad
ChildConstructor.prototype = ParentConstructor.prototype;
Though this technically works, any assignments to ChildConstructor.prototype will also be assigned to ParentConstructor.prototype because Objects are passed by reference and not by copy.
Inheriting the parent prototype attempt #3
// Almost there
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
This allows you to assign properties to ChildConstructor.prototype because it is an instance of a temporary anonymous function.
Properties that are not found on the instance of TempConstructor will then check it's prototype chain for the property, so you have successfully inherited the parent prototype. The only problem is that ChildConstructor.prototype.constructor is now pointing to TempConstructor.
Inheriting the parent prototype attempt #4
// Good
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;
All Together
var ParentConstructor = function(){
};
var ChildConstructor = function(){
ParentConstructor.call(this)
};
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;
You've successfully inherited from the parent class! Let's see if we can do better.
The inherits function
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor (currently set to TempConstructor )
};
var ParentConstructor = function(){
};
var ChildConstructor = function(){
ParentConstructor.call(this)
};
inherits(ChildConstructor, ParentConstructor);
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.