Inheriting more than once, keeping members private per instance - javascript

Basically, what I'm trying to do, is what has been discussed many times already. However, most examples feature only ClassA inheriting from ClassB. My situation is quite trivial, however doesn't seem to be addressed in the JavaScript topics that I have found.
ClassB extends ClassA, which has a member. ClassC and ClassD extend ClassB. However, when setting the only member in an instance of ClassC, this member is also set in members of ClassD. Let's look at an example:
function ClassA(data) {
var This = this;
This._data = {};
This._construct = function(data) {
if( undefined === data ) {
This._data = {};
return true;
}
This._data = data;
}
This._construct(data);
}
function ClassB() {
}
ClassB.prototype = new ClassA();
ClassB.prototype.constructor = ClassB;
function ClassC() { // Extends ClassB
}
ClassC.prototype = new ClassB();
ClassC.prototype.constructor = ClassC;
function ClassD() { // Extends ClassB
}
ClassD.prototype = new ClassB();
ClassD.prototype.constructor = ClassD;
var objectC = new ClassC();
var objectD = new ClassD();
objectC._data['somevar'] = 'asdasdasd';
console.log(objectC._data); // Object { somevar="asdasdasd"}
console.log(objectD._data); // Object { somevar="asdasdasd"}
If you set a breakpoint on line console.log(objectC._data);, you may see in the Watch window of FireBug that all prototypes are set correctly. It's really strange, because it is clear that the prototypes of ClassC and ClassD are separate instances created with the new keyword, and thus should not share members. Can someone explain please?
The _construct() function can be removed from ClassA, with no effect.
The var This = this line can be removed, and all consequent references to This can be changed to this, with no effect.

You need to have a call to super in each class, to have this pattern work. This is how you can ao it.
//Simplifying the construction part a bit.
function ClassA(data) {
this._data = data || {};
}
function ClassB(data) {
ClassA.call(this, data); //call super class (ClassA) constructor
//here you can initialize any ClassB specific variables
}
ClassB.prototype = new ClassA();
ClassB.prototype.constructor = ClassB;
function ClassC(data) { // Extends ClassB
ClassB.call(this, data); //call super class (ClassB) constructor
//here you can initialize any ClassC specific variables
}
ClassC.prototype = new ClassB();
ClassC.prototype.constructor = ClassC;
function ClassD(data) { // Extends ClassB
ClassB.call(this, data); //call super class (ClassB) constructor
//here you can initialize any ClassD specific variables
}
ClassD.prototype = new ClassB();
ClassD.prototype.constructor = ClassD;
var objectC = new ClassC();
var objectD = new ClassD();
objectC._data['somevar'] = 'asdasdasd';
console.log(objectC._data); // Object { somevar="asdasdasd"}
console.log(objectD._data); // Object {} -- empty for objectD
Now you can see that _data is not shared across instances.

Related

extending singleton class in es6

I need to extend a singleton class in JavaScript .
The problem that I am facing is that I get the class instance which I am extending from instead of only getting the methods of the class.
I have tried to remove super to not get the instance but then I got an error
Must call super constructor in derived class before accessing 'this' or returning from derived constructor
Code example:
let instanceA = null;
let instanceB = null;
class A {
constructor(options) {
if (instanceA === null) {
this.options = options;
instanceA = this;
}
return instanceA;
}
}
class B extends A {
constructor(options) {
if (instanceB === null) {
super()
console.log('real class is ' + this.constructor.name)
this.options = options
instanceB = this;
}
return instanceB;
}
}
const a = new A({
i_am_a: "aaaaaa"
});
const b = new B({
i_am_b: "bbbbbb"
}) // this change a
console.log(b.options)
console.log(a.options)
So, first of all there's a misconception here:
I have tried to remove super to not get the instance but then I got an error
super() calls the parent class' constructor on the created instance of the child class (i.e. what this is referencing). It does not return a parent class instance. See here for more information.
So, calling super() does not violate the singleton property of the parent class at all. It may well be only constructed a single time if implemented correctly.
With that in mind, you should improve your code a little bit.
A sensible change would be to remove the instance management from the constructors. One solution would be to use static constructors which either create the singleton if no instance exists or return the created instance.
Another one is to drop the arguments to the singleton class constructors. It doesn't really make sense to pass arguments to a class which is supposed to be instantiated once (you're never gonna do anything with the constructor arguments again). You could just make the arguments properties of the singleton right away. Here's a SO answer supporting this point for Java singletons.
A complete example with static constructors and without arguments looks like this:
let instanceA = null;
let instanceB = null;
let counters = { A: 0, B: 0 }; // count class instantiations
class A {
static getInstance() {
if (instanceA === null) {
instanceA = new A();
}
return instanceA;
}
whoami() {
const name = this.constructor.name;
return `${name} #${counters[name]}`;
}
constructor() {
counters[this.constructor.name] += 1;
}
}
class B extends A {
static getInstance() {
if (instanceB === null) {
instanceB = new B();
}
return instanceB;
}
constructor() {
super();
}
}
const a1 = A.getInstance();
const a2 = A.getInstance();
const a3 = A.getInstance();
const b1 = B.getInstance();
const b2 = B.getInstance();
const b3 = B.getInstance();
console.log(a1.whoami());
console.log(a2.whoami());
console.log(a3.whoami());
console.log(b1.whoami());
console.log(b2.whoami());
console.log(b3.whoami());
Note that B inherits whoami from A and that the constructor call counters are never incremented past 1.
Obviously with this approach you can make no guarantee the singleton property holds for each class unless only the static constructors are used to generate instances (since the constructors are still accessible). I think it's a good compromise though.
In JavaScript, a singleton is just an object literal.
const a = {
options: {
i_am_a: "aaaaaa"
}
};
const b = {
options: {
i_am_b: "bbbbbb"
}
};
If you really need a constructor function, you can just write a function that returns an object.
function makeSingleton(options) {
return {
options
}
}
const a = makeSingleton({i_am_a: "aaaaaa"});
const b = makeSingleton({i_am_b: "bbbbbb"});
There's no inheritance chain here, just two object literals. If you absolutely need a class, you can just create one, but it's an unnecessary waste of resources and typing.
class Singleton {
constructor(options) {
this.options = options;
}
}
const a = new Singleton({i_am_a: "aaaaaa"});
const b = new Singleton({i_am_b: "bbbbbb"});
In terms of inheriting, if that's something you really need, you can use Object.create() or Object.assign(), depending on your needs. Be aware that both are shallow - they only work a single layer deep so modifying the child's options property would modify the parent's options property as well.
const a = {
options: {
i_am_a: "aaaaaa"
},
getOptions() {
return this.options;
}
};
const b = Object.create(a);
b.options.i_am_b: "bbbbbb";
a.options.i_am_b; // -> "bbbbbb"
b.getOptions(); // -> { i_am_a: "aaaaaa", i_am_b: "bbbbbb" }
Of course, you could use Object.create() or Object.assign() on the options as well.
To be honest, I think you either need a couple of instances of the same class, or a simple object literal without any inheritance.
const instances = {}
class Singleton {
constructor() {
const instance = instances[this.constructor];
if (instance == null) {
return instances[this.constructor] = this;
}
return instance;
}
}
class Foo extends Singleton {
constructor() {
super();
this.foo = "foo";
}
}
class Bar extends Singleton {
constructor() {
super();
this.foo = "bar";
}
}
const foo1 = new Foo();
const foo2 = new Foo();
const bar1 = new Bar();
const bar2 = new Bar();
console.log(foo1 === foo2, bar1 === bar2, foo1 === bar1, foo1.foo = 123, foo2, bar1);
well i don't know if it the best solution but what i did is to check if the constructor name is different then the class name. if so then i let it create a new instance because that mean i try to extend the class
here is a working example of my test
let instanceA = null;
let instanceB = null;
class A {
constructor(options) {
this.options = options;
if (instanceA === null) {
instanceA = this;
}
if(this.constructor.name !== "A"){
return this;
}
return instanceA;
}
method1(){
console.log(this.constructor.name)
}
}
class B extends A {
constructor(options) {
if (instanceB === null) {
super(options)
instanceB = this;
}
return instanceB;
}
}
const a = new A({
i_am_a: "aaaaaa"
});a
const b = new B({
i_am_b: "bbbbbb"
})
const c = new A({
i_am_c: "ccccc"
});
const d = new B({
i_am_d: "ddddd"
})
console.log(a.options)
console.log(b.options)
console.log(c.options)
console.log(d.options)
a.method1();
b.method1();
c.method1();
d.method1();

Is it possible in javascript to inherit properties from another class - rather than an existing object?

For example in PHP if you wanted a class to inherit properties of another class you would reference the parent class
<?php
class BaseController {
// ....
}
class UserController extends BaseController {
// ....
}
However in javascript if you want a new class or object to inherit some properties from another class - it seems you need to assign an - already instantiated - object of the class you want to inherit from to your objects prototype.
e.g. If you want to create a brand new object and access the properties of an existing object:
var robot = {
active : "yes",
primeDirective : function() {
console.log("Must kill all humans!");
}
};
var bender = Object.create(robot);
bender.primeDirective(); => "Must kill all humans!"
or if you have an existing object, you can assign the existing object to prototype using __proto__
var robot = {
active : "yes",
primeDirective : function() {
console.log("Do a flip!");
}
};
var bender = {
name : "Bender Bending Rodriguez"
};
bender.__proto__ = robot;
bender.primeDirective(); => "Do a flip!"
both these methods require an already created object to inherit properties from, is it possible for a class definition to inherit from another class - similar to the extends functionality in PHP?
In ES5 JavaScript the correct way to derive a class is to use Object.create passing the base class's prototype, not an instance, and then to ensure that all functions are part of that prototype.
// a properly formed constructor function
function Robot(name) {
this.name = name;
}
// all functions belong on the prototype
Robot.prototype.primeDirective = function() {
...
}
// create derived class
function BendingUnit22(name) {
Robot.call(this, name); // invoke superclass constructor
}
// create and attach a new prototype object chained from the base class
BendingUnit22.prototype = Object.create(Robot.prototype);
// and re-attach the constructor
BendingUnit22.prototype.constructor = BendingUnit22;
// add new or overriding functions here
BendingUnit22.prototype.primeDirective = function() {
...
}
var bender = new BendingUnit22("Bender Bending Rodriguez");
You'll need to create a constructor (or an ES6 class) if you want to inherit a little less dynamically.
function Robot() {
this.active = true;
}
Robot.prototype.primeDirective = function() {
console.log("Must kill all humans!");
};
var bender = new Robot(); // Yey!
To create a new inheriting constructor:
function HumanoidRobot() {
Robot.apply(this, arguments);
this.legs = 2;
}
HumanoidRobot.prototype = Object.create(Robot.prototype);
HumanoidRobot.prototype.constructor = HumanoidRobot;
This process becomes a lot easier with ES6 classes, which hide all this ugliness from you!
class Robot {
constructor() {
this.active = true;
}
primeDirective() {
console.log("Must kill all humans!");
}
}
class HumanoidRobot extends Robot() {
constructor() {
super()
this.legs = 2;
}
}
No, there is no built in mode for extending classes in Javascript, because it is not a class based but prototype based language.
However, there are many frameworks that implement the 'extend' behaviour, for example in Prototype:
var robot = Class.extend({ ... });
var bender = robot.extend({ ... });
http://ejohn.org/blog/simple-javascript-inheritance/
But many other frameworks support the same, for example Underscore _.extend()
http://underscorejs.org/#extend
There are 3 kind of inheritance possible in JavaScript.
Pseudo Classical (Like the one you are looking for)
/**
* Create a new constructor function, whose prototype is the parent object's prototype.
* Set the child's prototype to the newly created constructor function.
**/
var extendObj = function (childObj, parentObj) {
var tmpObj = function () {}
tmpObj.prototype = parentObj.prototype;
childObj.prototype = new tmpObj();
childObj.prototype.constructor = childObj;
};
(https://jsfiddle.net/nikdtu/4wzuwhqw/)
Functional
(https://jsfiddle.net/nikdtu/eh7u4pxd/)
Prototypal (Object.create)
(https://jsfiddle.net/nikdtu/dnjkx8w1/)
Luckily I documented that during a project and captured those JSfiddles.
I hope You will find the required help from these.
I think this is what you are looking for
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);
}
// inherit Person
Student.prototype = new Person();
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true

Javascript prototype banals: inheritance

How can i override this.property at runtime and for each instance, without making a new class and eventually calling doAnotherThing on the parent?
var ThridPartyObject = function() {
this.property = 'value';
this.doOneThing= function() { /* */ }
this.doAnotherThing= function() { /* */ }
};
No luck with:
ThridPartyObject.prototype = {
property: 'myvalue',
doOneThing: function() { // Override only this function and call the other
return this.doAnotherThing();
}
};
EDIT: forgot to say that property may or may not exists.
I need this because, in backbone.js, i have to define a custom property for all my model instances, and some function should act in a different way of original backbone ones. Here is how backbone defines a Backbone.Model (_.extend is from underscore.js):
var Model = Backbone.Model = function(attributes, options) {
var defaults;
attributes || (attributes = {});
if (options && options.collection) this.collection = options.collection;
if (options && options.parse) attributes = this.parse(attributes);
if (defaults = getValue(this, 'defaults')) {
attributes = _.extend({}, defaults, attributes);
}
this.attributes = {};
this._escapedAttributes = {};
this.cid = _.uniqueId('c');
this.changed = {};
this._silent = {};
this._pending = {};
this.set(attributes, {silent: true});
// Reset change tracking.
this.changed = {};
this._silent = {};
this._pending = {};
this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments);
};
// Attach all inheritable methods to the Model prototype.
_.extend(Model.prototype, Events, {
// cut
});
If the object is truly "third party," and outside your control, then the creators of it have chosen a pattern that is not compatible with prototypal inheritance (sometimes called the "closure pattern"). You will not be able to override, globally, any properties of ThirdPartyObject instances, because every ThirdPartyObject gets property, doOneThing, and doAnotherThing newly assigned to it at construction time.
In this case the only solution would be to create a new factory function wrapping the original:
function modifiedThirdPartyObjectFactory() {
var x = new ThirdPartyObject();
x.property = "myvalue";
return x;
}
var mtpo = modifiedThirdPartyObjectFactory();
A pattern that does use prototypal inheritance would work as follows:
function ThirdPartyObject() {
this.property = "value";
}
ThirdPartyObject.prototype.doOneThing = function () {
};
ThirdPartyObject.prototype.doAnotherThing = function () {
};
This pattern sets instance properties, usually data, in the constructor. Whereas shared properties, usually methods, go on the prototype. The original code made all properties instance properties, so there are no shared properties you can modify that would result in your changes being reflected across all instances.
You're actually thinking about it backwards.
Prototype would be like the parent class.
It's not exactly-like the parent class in a class-based language (there are a LOT of differences).
But in this instance, for the sake of inheriting properties/methods, prototype would be the parent class.
When you make a Foo, Foo is the child, for all intent and purpose in your problem.
When you do this:
function Foo () { this.method = function () {}; this.property = {}; }
Foo.prototype.method = function () {};
Foo.prototype.property = {};
Foo.prototype.other_property = 3;
It's similar to saying:
PrototypeClass {
public virtual property = {};
public other_property = 3;
public virtual method ( ) { }
}
Foo inherits BaseClass {
public override property = {};
public override method () {}
}
var foo = new Foo();
The constructor for Foo is overriding everything up the chain in the prototype, that has the same name.
When Foo doesn't have a method or a property inside of it, THEN it looks upstream, through its inheritance/prototype chain.
So if you want to override methods/properties of Foo, then you MUST override the instance of new Foo().
Your options for that are pretty much just to build a wrapper around Foo... ...like:
function FooPlusPlus () {
var foo = new Foo();
foo.plus = function () { this.doSomething(); console.log(this.val); };
foo.plusPlus = function () { foo.plus(); console.log(this.other_val); };
return foo;
}
var fooPlusPlus = FooPlusPlus(); // ***NO NEW***
...or to create a function which simply extends a pre-existing object (whether it's a "class" or a "dictionary" or a function, or an array) with whatever added properties/functionality you want to extend them with:
var extendObj = function (subject, extensions) {
var key = "";
for (key in extensions) { if (extension.hasOwnProperty(key)) {
subject[key] = extensions[key];
}}
}
var regularFoo = new Foo();
extendObj(regularFoo, { awesomeFunc : function () { if (typeof this.doSomething === "function") { this.doSomething(); }}, coolProp : "Bob" });
JS gives you the freedom to let anything inherit anything, as long as you aren't expecting strings or numbers to act like classes with custom data, without careful manipulation of the Core objects.

Static variables with John Resig's simple class pattern?

I'm referring to this article.
In it, he defines a function that looks something like this:
function makeClass() {
return function _class() {
if(this instanceof _class) {
if(typeof this.init === 'function') {
this.init.apply(this, arguments);
}
} else {
throw new Error('Constructor called as a function');
}
};
}
And then you can use it with something like this:
var MyClass = makeClass();
MyClass.prototype = {
init: function(width, height) { ... },
clear: function(ctx) {... },
draw: function(ctx) { ... }
}
But now I want to initialize some static variables that should be shared across all instances. How do I do that?
Well, the easiest approach is to define a static variable as a prototype property:
MyClass.prototype.xxx: 3, // ...
var t1 = new MyClass();
console.log(t1.xxx); // 3
... but it won't behave as static properties in other languages usually do:
var t2 = new MyClass();
t2.xxx = 5;
console.log(t1.xxx); // still 3 :(
The other way around is to use the fact that properties might be attached to functions as well:
MyClass.xxx = 3;
... but that narrows the ways we can use this property (it can't be called by t1.xxx from the previous examples).
There's another way, though. One can define static properties as variables, local to init method, accessible by methods, defined... in this init method as well. ) Like this.
init: function() {
var xxx = 3;
MyClass.prototype.getXXX = function() {
return xxx;
};
MyClass.prototype.setXXX = function(newXXX) {
xxx = newXXX;
}
}
Then all one can use this property simply by this:
var t1 = new MyClass();
var t2 = new MyClass();
console.log(t1.getXXX()); // 3
console.log(t2.getXXX()); // 3
t1.setXXX(5);
console.log(t1.getXXX()); // 5 now
console.log(t2.getXXX()); // 5 as well, behold the power of closures!
And here's a fiddle used.
UPDATE: this approach is better be used, I suppose, when we need to work with a (sort of) container of the static class data, that is to be shared by all objects - but we don't know exactly what can actually be stored in this container. Then we use just two functions - getStatic and setStatic - to store and retrieve data by string keys or some other identifiers. It may seem a bit confusing, and it is, but I think it may be worth an effort. )
Just add it to MyClass itself.
MyClass.myVariable = 42;
It's not really static in the Java/C# sense, but gives you the same effect.
I "solved" this problem by using a naming convention.
I wanted the convenience of the Class.extend({ }) syntax, but also a way to declare "static" properties within it.
I opted for a leading underscore to declare a static property, although you could do whatever you liked.
Usage:
var myClass = Class.extend({
_staticProperty: 1337
, instanceProperty: 'foo'
, instanceMethod: function() { }
, ctor: function() {
this.base();
}
});
note I've renamed init and this._super() from the original code
And the code:
/* Simple JavaScript Inheritance
* Modified by Andrew Bullock http://blog.muonlab.com to add static properties
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function () {
var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\bbase\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function () { };
// Create a new Class that inherits from this class
Class.extend = function (prop) {
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// The dummy class constructor
function Class() {
// All construction is actually done in the ctor method
if (!initializing && this.ctor)
this.ctor.apply(this, arguments);
}
// Copy static properties from base
for (var name in this) {
if (name.substr(0, 1) == '_')
Class[name] = this[name];
}
// Copy the properties over onto the new prototype
for (name in prop) {
// Check if we're overwriting an existing function
if (typeof prop[name] == "function" && typeof base[name] == "function" && fnTest.test(prop[name])) {
prototype[name] = (function(name, fn) {
return function() {
var tmp = this.base;
// Add a new .base() method that is the same method
// but on the super-class
this.base = base[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this.base = tmp;
return ret;
};
})(name, prop[name]);
} else if (name.substr(0, 1) == '_') {
Class[name] = prop[name];
} else {
prototype[name] = prop[name];
}
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
If you don't care about browser support, you could also use a WeakMap of constructor/static properties pairs. Here's the idea: http://jsfiddle.net/DfNNU/2/. This requires MyClass.prototype.constructor, which you should not discard. So, you'd need to add back constructor: MyClass to the prototype.
var statics = (function() {
var map = new WeakMap;
return function(inst) {
var ctor = inst.constructor;
return map.get(ctor) || map.set(ctor, {});
};
})();
Use it like:
var a = function() {};
var b = function() {};
var inst1 = new a;
var inst2 = new a;
var inst3 = new b;
statics(inst1).foo = 123;
statics(inst3).foo = 456;
console.log( statics(inst1).foo ); // 123
console.log( statics(inst2).foo ); // 123
console.log( statics(inst3).foo ); // 456
I've modified John Resig's class to provide copy over the parent's static members to the new class, which adds this:
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
Here's a fiddle.
// This is a modified version of John Resig's simple inheritence class to add copying of static methods
// The new code is the for loop commented with "add in the static members"
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
//add in the static members
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
function addText(text) {
document.getElementById('greetings').innerHTML = document.getElementById("greetings").innerHTML + '<br>' + text;
}
//parent class with a prototype method and two static methods
var Parent = Class.extend({
hello: function () {
addText('parent.hello');
}
});
Parent.static = function() {
addText('Parent.static');
}
Parent.overrideStatic = function() {
addText('Parent.overrideStatic');
}
//child class that overrides one of the parent's static methods
var Child = Parent.extend();
Child.overrideStatic = function() {
addText('Child.overrideStatic');
}
var parent = new Parent();
parent.hello();
Parent.static();
var child = new Child();
child.hello(); //should output parent.hello
Child.static(); //should output Parent.static
Child.overrideStatic();
<div id="greetings"></div>
Pass in an optional list of static members in the call to 'extend'. This method adds the static properties (if any) to a 'statics' attribute on the constructor function.
Code Changes
Changes as follows. These lines added just after the 'dummy class constructor' code:
if(staticProp) {
Class.statics = [];
for (var name in staticProp) {
!Class.statics[name] && (Class.statics[name] = staticProp[name]);
}
}
An additional argument 'staticProp' added when type is declared in order to allow introduction of static members at this stage:
Class.extend = function(prop,staticProp) {
A fiddle can be found here, includes some tests.
Usage Examples
Can define statics at type declaration time like so using the second optional constructor argument:
var A = Class.extend({},{myStatic:1});
Can access/define statics inside an instance method:
var B = Class.extend({test:function(){B.statics.myStatic=2;}});
Or from outside an instance:
A.statics.myStatic=3;
Example with requirejs:
Put Class.js in the baseUrl folder. Example new class definition. Not mandatory to name the file of the new class the same as the 'var C' (i.e. C.js) but probably better for readability so references to the C name within the class's methods are aligned to any external references to its static members:
define(['Class'],function($) {
var C = Class.extend({
init: function(params){
C.statics.myStatic++; // access static data
}
},{
myStatic: 123
});
return C;
});
Another class in D.js refers to static data in class C:
define(['Class', 'C'],function($,C) {
var D = Class.extend({
init: function(params){
C.statics.myStatic++; // static data of another class
}
},{});
return D;
});

Static/shared property and method in JavaScript

I'm trying to have a 'class' in JS which tracks how many instances of itself have been instantiated. I am attempting to do so like this...
var myNamespace = {};
myNamespace.myClass = function () {
//fails here as .getNetInstanceNo() not recognised...
var instanceNumber = myNamespace.myClass.getNextInstanceNo();
return {
instanceNo : function() { return instanceNumber; }
}
};
myNamespace.myClass.InstanceNo = 0; //static property?
//should the class itself have this method added to it...
myNamespace.myClass.prototype.getNextInstanceNo = function () { //static method?
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo() );
However this fails as the getNextInstanceNo function is not recognised. Even though I think I'm adding it through the myClass.prototype.
What am I doing wrong?
prototype is an object from which other objects inherit properties, as in when you create an instance of an object and that object doesn't have a property/method, when called, the prototype of the class in which the object belongs to is searched for that property/method, here's a simple example:
function Animal(){};
Animal.prototype.Breathe = true;
var kitty= new Animal();
kitty.Breathe; // true (the prototype of kitty breathes)
var deadCat = new Animal();
deadCat.Breathe = false;
deadCat.Breathe; // false (the deadCat itself doesn't breath, even though the prototype does have breath
As you said yourself, you don't need to define getNextInstanceNo on prototype, since that's not how static methods are defined on JavaScript, leave it right right there on the class itself, instead you can define the instanceNo method on prototype, here's how:
var myNamespace = {};
myNamespace.myClass = function () {
this.instanceNumber = myNamespace.myClass.getNextInstanceNo();
};
myNamespace.myClass.prototype.instanceNo = function () {
return this.instanceNumber;
};
myNamespace.myClass.InstanceNo = 0;
myNamespace.myClass.getNextInstanceNo = function () {
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo());

Categories

Resources