If I use constructor functions for my objects and prototype for shared functionality I would like to mixin shared functionality (functions) to the object's prototype but instance specific (this varaibles) to the object instances.
To add the prototype part I found this pattern. To set instance variables that are assumed to be there by the prototype functions I came up with an init (one for each mixin).
Here is a simple example:
var mixIn=function(target,source){
for(fn in source){
if(source.hasOwnProperty(fn)){
target.prototype[fn]=source[fn];
}
}
};
var SpeakEnable = {
say:function(){
console.log(this.message);
},
initSpeak:function(){// for initializing instance vars
this.message="Hello World Mixed in!";
this.object=[];
}
};
var Person=function(){
this.initSpeak();//have to init instance vars
};
// set up inheritance
// set up Person.prototype
// set speak enable
mixIn(Person,SpeakEnable);
var lulu=new Person();
lulu.say();
var june=new Person();
console.log(june.say===lulu.say);//true
console.log(june.object===lulu.object);//false
This all works fine and dandy but initializing the instance variables is where I have some problem with. It somehow doesn't seem to be a very clean way. When I mix in several mixins the Person constructor function has to call all the init functions to set up the instance variables. Forgetting to call it will result in strange errors (in this case console logging undefined when say is called on an instance).
So the question is: is there a cleaner way to setup initial instance variables that are assumed to be there by the mixin functions?
You could inherit all mixable objects from a base object that ensures proper initialization. This is a clean way of achieving your goal.
The following code demonstrates this principle:
//------------ framework
var inherits = function(childCtor, parentCtor) {
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};
var mixIn=function(target,source){
for(fn in source){
if(source.hasOwnProperty(fn) && fn.name != 'init'){
target.prototype[fn]=source[fn];
}
}
if (typeof source.init == 'function') {
if (target.prototype._mixInits === undefined) {
target.prototype._mixInits = [];
}
target.prototype._mixInits.push(source.init);
}
};
// all objects that can be mixin's should inherit from
// this object in order to ensure proper initialization
var Mixable = function() {
var mixInits = this.__proto__._mixInits;
if (mixInits !== undefined) {
for (var i = 0; i < mixInits.length; i++) {
mixInits[i].call(this);
}
}
};
//------------ testcode
var SpeakEnable = {
say:function(){
console.log(this.message);
},
init:function(){
console.log('say init called');
this.message="Saying Hello World Mixed in!";
this.object=[];
}
};
var WalkEnable = {
walk:function(){
console.log(this.walk_message);
},
init:function(){
console.log('walk init called');
this.walk_message="Walking step 1.2.3.";
}
};
var Person=function() {
Mixable.call(this);
};
inherits(Person, Mixable);
mixIn(Person,SpeakEnable);
mixIn(Person,WalkEnable);
var lulu=new Person();
lulu.say();
lulu.walk();
Related
I find this is most recommended way to do inheritance in javascript.
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
}
what if I already have methods in child's prototype, aren't they will overwrite, shouldn't we preserve them.
function extend(Child, Parent) {
var c = child.prototype;
var oldProto = new C();
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
for(var i in oldProto ){
Child.prototype[i] = oldProto[i]
}
}
I'm not sure if this is any good to you, but it's well important to remember: prototypes are not the same things as classes. What you're doing is trying to make JS behave like a traditional OO language, which is trying to teach a dolphin to dance ballet, or forcing a tiger to become vegan: Admirable, but destined to end in tears.
I can't really see why you'd want to use the extend function to do whatever it is you're trying to do. Why not simply use this:
function Parent()
{};
function Child()
{};
//augment parent proto
Parent.prototype.parentMethod1 = function()
{};
//set Child's proto to Parent
Child.prototype = new Parent();
Child.prototype.constructor = Child;
//Then augment the Child's prototype
Child.prototype.childMethod1 = function()
{};
var foo = new Child();
foo.parentMethod1();//works
foo.childMethod1();//works, too
IMO, this solves the problem entirely. Sure, it's a tad more verbose, but OOP always is.
The pattern you're trying to achieve is called multiple inheritance. And it's highly not recommended for the use because of the issue you're experiencing, called diamond problem. Just use mixin pattern instead.
The code below is the one of the best I have seen for doing inheritance in JavaScript.
Object.create(proto [, propertiesObject ]) is discussed on MDN here.
Below, Jon defines a base empty object called ExtendBase then adds a function property called extend which is not enumerable which takes as its argument a single new object.
That object should contain enumerable properties such as methods and data that will be added to the base object.
He gets all the enumerable properties from the passed object, then creates an array of the necessary descriptors to pass into Object.create using those properties' names. He then uses the parent object as the prototype and resultant descriptors as new properties to be added to the child object directly in the Object.create() call.
As you can see, you can use an object argument with properties, including methods, to extend a parent without losing that passed object's properties with the result being a child object with the parent as the prototype and the enumerable objects of the passed object added directly to the child.
However, this maintains a clean prototype chain while intending to extend parent objects using other objects which are created sanely to extend the parent into a new child in a way that makes sense:
Live sample here (Press F12 in Chrome for console output, or use FireBug in FireFox, etc.)
JavaScript:
// Original Author: FireFly - Jonas Höglund - ##javascript channel
// on irc.freenode.net - see THANKS File. Updated to private data
// members and passable initial parameters by Scott Sanbar
///////////////
// Library code
///////////////
var ExtendBase = {};
Object.defineProperty(ExtendBase, 'extend', {
enumerable:false, value:function (obj) {
'use strict';
var descs = {};
Object.getOwnPropertyNames(obj).forEach(function (key) {
descs[key] = Object.getOwnPropertyDescriptor(obj, key)
});
return Object.create(this, descs);
}
});
///////////////
// Sample Usage
///////////////
function PersonObj(nam) {
return {
name:new function () {
var name = nam;
this.set = function (value) {
name = value;
};
this.get = function () {
return name;
}
},
// A person can tell you its name.
talk:function () {
return "Hello, I'm " + this.name.get();
}
}
}
;
function WorkingPersonObj(occ) {
return {
occupation:new function () {
var occupation = occ;
this.set = function (value) {
occupation = value;
};
this.get = function () {
return occupation;
}
},
// A working person also tells you their occupation when they talk.
talk:function () {
return Person.talk.call(this) + " and I am a " + this.occupation.get();
}
}
}
;
var hush = {
hush:function () {
return "I am supposed to be quiet";
}
};
var Person = ExtendBase.extend(new PersonObj('Harry'));
var WorkingPerson = Person.extend(new WorkingPersonObj('wizard'));
var wp1 = WorkingPerson.extend(hush);
console.log(wp1.talk()); // "Hello, I'm Harry and I am a wizard"
console.log(wp1.hush()); // "I am supposed to be quiet"
wp1.name.set("Elijah");
wp1.occupation.set("prophet");
console.log(wp1.talk()); // "Hello, I'm Elijah and I am a prophet"
console.log(wp1.name.get());
console.log(wp1.occupation.get());
I have code that looks like this:
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
}
Adding methods to baseClass is fine, I just use
baseClass.prototype.newMethod = function () {
// NEW CODE
}
My question is how should I add methods to subClass? Is the only way to simply make it a public method?
######## EDIT ##############
OK so I've rearranged the code so the subClass is outside the baseClass. I pass in baseClass so subClass can still access the properties of the instance of baseClass.
var baseClass = function() {
var base = this;
this.property_a = 1;
this.property_b = 5;
var sub = new subClass(base);
// CODE
}
var subClass = function(parent) {
var sub = this;
this.property_c = 1;
this.method_a = function() {
return sub.property_c + parent.property_a;
}
// MORE CODE
}
this is fine and works, but now I have a new problem of when I add a method using prototype:
subClass.prototype.method_b = function(){
return sub.property_c + parent.property_b;
}
I get an error saying parent isn't defined.
Basically I have a fairly simple web application that has two sides, a viewing side and an editing side. I build the base class which includes everything necessary for viewing, and I want to add the methods required for editing in a different file so they're only loaded when a user is on the editing page.
Why do you declare that subclass in the base class? Doesn't make sense to me.
You can add to the subclass's prototype whereever it is in you scope. In your code it would be
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
subClass.prototype = {
...
}
}
But I'd suggest to put it out of the base class constructor. If you want it private for some reason, add a closure:
(function(){
baseClass = function() { // public
// CODE
}
baseClass.prototype = {...};
var subClass = function() { // private
// MORE CODE
}
subClass.prototype = Object.create(baseClass.prototype);
subClass.prototype.newMethod = function () { ... }
})()
EDIT to answer the extended question:
Ah, subClass doesn't inherit from baseClass! We had expected that, otherwise it may be OK to have it inside the constructor. Then, the same prototype could have been added to each of the different subClass constructors:
var subproto = {
method_b: = function(){
// manipulate "this"
},
...
};
function baseClass() {
// some code
function sub() {
// is a constructor for subs which belong to this specif base intance
...
}
sub.prototype = subproto; // the sub constructors of each base instance
// have the same prototype
var x = new sub(),
y = new sub(); // example usage of the sub constructor
}
baseClass.prototype = {...}
Else, if you want one common sub constructor (outside of function baseClass), you may give the base instance the sub belongs to as an argument to the constructor - as you did. Of course the sub (both internal and external methods) can only access public properties of that base instance.
The mistake you made in your rearranged code is that your prototype ("external") methods tried to access the private parent variable from the sub constructor. As you say, "error saying parent isn't defined".
var subClass = function(parent) {
var sub = this;
this.parent = parent; // make it public
this.property_c = 1;
this.method_a = function() {
return sub.property_c + parent.property_a;
}
// MORE CODE
}
subClass.prototype.method_b = function(){
// prototype functions can only access public properties
// i.e. privileged methods, public attributes and other prototype properties
return this.property_c + this.parent.property_b;
}
You will have to define the methods in the same context as you define subClass:
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
subClass.prototype.newMethod = function () { ... }
}
If that's not possible, then you will need to expose subClass to the appropriate context or provide a mechanism from baseClass to extend subClass.
If you really want to keep the subclass private, you could hide the definitions in a closure:
var BaseClass = (function() {
function BaseClass() { ... };
function SubClass() { ... };
BaseClass.prototype.foo = function() { ... };
SubClass.prototype.foo = function() { ... };
return BaseClass;
})();
I have personally found this kind of closure-enforced protection to be more trouble than it's worth (ex, makes debugging more difficult)… But if you wanted to do it, that's how you would.
I currently know two ways to construct singletons in JavaScript. First:
var singleton = {
publicVariable: "I'm public",
publicMethod: function() {}
};
It is perfect except that it does not have a constructor where I could run initialization code.
Second:
(function() {
var privateVariable = "I'm private";
var privateFunction = function() {}
return {
publicVariable: "I'm public",
publicMethod: function () {}
}
})();
The first version does not have private properties nor does it have a constructor, but it is faster and simpler. The second version is more complex, ugly, but has a constructor and private properties.
I'm not in a need for private properties, I just want to have a constructor. Is there something I am missing or are the two approaches above the only ones I've got?
function Singleton() {
if ( Singleton.instance )
return Singleton.instance;
Singleton.instance = this;
this.prop1 = 5;
this.method = function() {};
}
Here is my solution with closures:
function Singleton() {
Singleton.getInstance = (function(_this) {
return function() { return _this; };
})(this);
}
Test:
var foo = new Singleton();
var bar = Singleton.getInstance();
foo === bar; // true
If you are just looking for a place to initialise your singleton, how about this?
var singleton = {
'pubvar': null,
'init': function() {
this.pubvar = 'I am public!';
return this;
}
}.init();
console.assert(singleton.pubvar === 'I am public!');
Simple and elegant.
var singleton = new function() { // <<----Notice the new here
//constructorcode....
this.publicproperty ="blabla";
}
This is basically the same as creating a function, then instantly assiging a new instace of it to the variable singleton. Like var singleton = new SingletonObject();
I highly advice against using singletons this way in javscript though because of the execution order is based on where in the file you place the object and not on your own logic.
What about this?
var Singleton = (function() {
var instance;
// this is actual constructor with params
return function(cfg) {
if (typeof instance == 'undefined') {
instance = this;
this.cfg = cfg;
}
return instance;
};
})();
var a = new Singleton('a');
var b = new Singleton('b');
//a === b; <-- true
//a.cfg <-- 'a'
//b.cfg <-- 'a'
I make it an actual Singleton with static functions and no this like so:
class S {
//"constructor"
static init() {
//Note: Since it's a singleton, there's no "this" instance.
//Instead, you store variables directly on the class.
S.myVar = 7;
}
static myOtherFunc() {
alert(S.myVar);
}
}
//Immediately call init() to make it the "constructor".
//Alternatively, you can call init() elsewhere if you'd
//like to initialize it at a particular time.
S.init();
//Later:
S.myOtherFunc();
S.myVar = 10;
Recently I saw the following code that creates a class in javascript:
var Model.Foo = function(){
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
if(typeof Model.Foo._init === 'undefined'){
Model.Foo.prototype = {
func1 : function(){ //...},
func2 : function(){ //... },
//other prototype functions
}
}
Model.Foo._init = true;
}
// Instantiate and use the class as follows:
var foo = new Model.Foo(); foo.func1();
I guess the _init variable is used to make sure we don't define the prototypes again. Also, I feel the code is more readable since I am placing everything in a function block (so in oop-speak, all attributes and methods are in one place).
Do you see any issues with the code above? Any pitfalls of using this pattern if I need to create lots of classes in a big project?
This is a weird Javascript pattern that I would never use to develop object-oriented JS code. For one thing, Model.Foo._init === 'undefined' never evaluates to true if Model.Foo._init is anything but the string 'undefined'; therefore, the code
Model.Foo.prototype = {
func1 : function(){ /* ... */},
func2 : function(){ /* ... */},
//other prototype functions
}
will not run unless that condition holds true. (Perhaps the author meant to add a typeof, as in typeof Model.Foo._init === 'undefined'? I don't know.)
Addressing your concern about "[making] sure we don't define the prototypes again", this is already achieved with:
Model.Foo = function() {
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
};
Model.Foo.prototype = {
func1 : function() { /* ... */},
func2 : function() { /* ... */}
//,other prototype functions
};
// Instantiate and use the class as follows:
var foo = new Model.Foo();
foo.func1();
which is along the lines of what I recommend if you aren't using a framework.
Basically, the answer to your question is: if you use this non-standard pattern for development, then other programmers, maybe even yourself a few months later, will find it difficult to extend and work with.
It just seems unnecessarily complex. You need to be disciplined to not use any parameters or local variables of Model.Foo in the implementation of the prototype extension. Its odd to overwrite the entire .prototype object and not just add individual members as well. Why not just do this the normal way?
var Model.Foo = function(){
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
}
Model.Foo.prototype.func1 = function(){ //...};
Model.Foo.prototype.func2 = function(){ //... };
alternate allowing per-instance member variables private
var Model.Foo = function(){
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
this.func1 = function(){ //...};
this.func2 = function(){ //... };
}
A few things stand out as potentially troublesome:
Foo.prototype is set to a simple object, which can't extend anything using this pattern.
Where is the "private stuff" used? Every time you create a new object, you create new private variables, which seemingly can only be used in the functions defined in Foo.prototype, which should only be run once.
It's kind of a mess, and there are details/examples all over the web of better was to do this.
The following example illustrates a pattern that I personally developed over time.
It exploits scoping to allow private fields and methods.
Employee = (function(){
// private static field
var staticVar;
// class function a.k.a. constructor
function cls()
{
// private instance field
var name = "";
var self = this;
// public instance field
this.age = 10;
// private instance method
function increment()
{
// must use self instead of this
self.age ++;
}
// public instance method
this.getName = function(){
return cls.capitalize(name);
};
this.setName = function(name2){
name = name2;
};
this.increment = function(){
increment();
};
this.getAge = function(){
return this.age;
};
}
// public static field
cls.staticVar = 0;
// public static method
cls.capitalize = function(name){
return name.substring(0, 1).toUpperCase() +
name.substring(1).toLowerCase();
};
// private static method
function createWithName(name)
{
var obj = new cls();
obj.setName(cls.capitalize(name));
return obj;
}
return cls;
})();
john = new Employee();
john.setName("john");
mary = new Employee();
mary.setName("mary");
mary.increment();
alert("John's name: " + john.getName() + ", age==10: "+john.getAge());
alert("Mary's name: " + mary.getName() + ", age==11: "+mary.getAge());
I need to extend a class, which is encapsulated in a closure. This base class is following:
var PageController = (function(){
// private static variable
var _current_view;
return function(request, new_view) {
...
// priveleged public function, which has access to the _current_view
this.execute = function() {
alert("PageController::execute");
}
}
})();
Inheritance is realised using the following function:
function extend(subClass, superClass){
var F = function(){
};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
StartController.cache = '';
if (superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
I subclass the PageController:
var StartController = function(request){
// calling the constructor of the super class
StartController.superclass.constructor.call(this, request, 'start-view');
}
// extending the objects
extend(StartController, PageController);
// overriding the PageController::execute
StartController.prototype.execute = function() {
alert('StartController::execute');
}
Inheritance is working. I can call every PageController's method from StartController's instance. However, method overriding doesn't work:
var startCont = new StartController();
startCont.execute();
alerts "PageController::execute".
How should I override this method?
It doesn't work because StartController calls PageController which adds an execute property to your object, so the execute property of StartController.prototype is not used.
For your overriding to work, you have to either :
1) define PageController.prototype.execute as the execute method of PageController. It won't work because then the function doesn't have access to _current_view.
2) define StartController.execute in the object constructor :
var StartController = function(request){
// calling the constructor of the super class
StartController.superclass.constructor.call(this, request, 'start-view');
// overriding the PageController::execute
this.execute = function() {
alert('StartController::execute');
}
}
// extending the objects
extend(StartController, PageController);
edit:
So you want for StartController.execute to access _current_view, which is impossible as long as _current_view is part of a closure that StartController is not part of. You might have to proceed like this:
(function () {
var _current_view;
window.PageController = function(request, new_view) {
...
this.execute = function() { ... }
}
window.StartController = function(request) {
StartController.superclass.constructor.call(this, request, 'start-view');
this.execute = function() { ... }
}
extend(StartController, PageController);
}()
var startCont = new StartController();
startCont.execute();
And if you want some kind of protected behavior, you might want to try this trick:
(function() {
var token = {};
window.Class1 = function() {
this.protectedMethod = function(tok) {
if(tok != token) return; // unauthorized
...
}
}
window.Class2 = function() {
new Class1().protectedMethod(token); // access granted
}
})()
new Class1().protectedMethod(); // access denied
There's no such thing as a package in javascript, so your possibilities are limited. You can certainly not have any kind of privileges among functions/objects/constructors that are not part of the same script. None that I know of, at least. Except maybe querying a server for some kind of authorization.