How to implement inheritance in JS Revealing prototype pattern?
There are no protected variables/properties in JavaScript. Though, you can reuse "private" variables when you declare the inheriting classes in the same scope, which seems possible in your case when the private variables are only "hidden utilities" of your prototype.
MyNamespace.Person = function Person(params) {
// private variables and functions, individual for each Person instance
var anything, id;
function execute_something() {}
// public properties:
this.name = "";
this.getId = function getId(){
// called a "privileged function", because it has access to private variables
}
}
MyNamespace.American = function(params) {
MyNamespace.Person.call(this, params); // inherit name and getId()
}
(function() { // new scope for
// hidden utility functions and other private things
function foo() { }
function helpJSON() { }
function fromJSON() { }
var bar;
(function(personProto) { // new scope for prototype module (not explicitly needed)
// "private" /static/ variables (and functions, if you want them private)
var personCount = 0;
personProto.clone = function clone() {
return this.constructor(myself); // or something
};
personProto.toJSON = function toJSON() {
// use of helpJSON()
};
personProto.fromJSON = fromJSON; // direct use
})(MyNamespace.Person.prototype);
(function(amiProto) {
// just the same as above, if needed
amiProto.special = function() {
// use foo() and co
};
})( MyNamespace.American.prototype = Object.create(MyNamespace.Person.prototype) );
})();
This is the JavaScript way of inheritance, which means American's prototype inherits the clone(), toJSON() and fromJSON() functions automagically from the Person's prototype. Of course overwritable. And the feature is
new MyNamespace.American() instanceof MyNamespace.Person; // true
Of course, if you don't need that, and want use the more module-like way, you could reuse the utility functions, i.e. just copy them:
(function() {
// hidden utility functions and other private things
var bar;
var personCount;
function foo() { }
function helpJSON() { }
function fromJSON() { }
function clone() {
return this.constructor(myself); // or something
}
function toJSON() { }
(function(personProto) { // new scope, not really needed
// private variables are useless in here
personProto.clone = clone;
personProto.toJSON = toJSON;
personProto.fromJSON = fromJSON;
})(MyNamespace.Person.prototype);
(function(amiProto) { // new scope, not really needed
// copied from personProto
amiProto.clone = clone;
amiProto.toJSON = toJSON;
amiProto.fromJSON = fromJSON;
// and now the differences
amiProto.special = function() {
// use foo() and co
};
})(MyNamespace.American.prototype);
})();
Creating inheritance on revealing modular pattern objects
$.extend(this, foo);
this
is not the object which you return from the function below (in fact it cannot be since it's created after this call), but the global object - check MDN's introduction to the this
keyword.
For what you want to do, there are two ways:
Copy all properties from
foo
onto yourbar
object after it is created:var bar = (function() {
…
return {…};
})();
$.extend(bar, foo);You can do that as well directly on the returned object:
return $.extend({…}, foo);
A variant of this pattern allows you to overwrite
foo
properties. Copyfoo
into an empty object, then write yourbar
properties to it:return $.extend({}, foo, {…});
Use prototypical inheritance. Create an object that inherits its properties from
foo
, and then write yourbar
properties to it:return $.extend(Object.create(foo), {…});
Now when
foo
changes afterward, you still can access those new properties onbar
(unless they're shadowed by own properties). Notice thatObject.create
might not be supported in legacy environments, but you can easily shim it.
As noted by @raina77ow, your doBarStuff
function is flawed too. The doFooStuff
function is not in the scope of your function, and you cannot change that. You never will be able to access the private declared functions and variables from the foo
module, only those that are public - if you did need them, consider a different pattern or app design. However, doFooStuff
is a property on the exported (public) foo
object, from which bar inherits (regardless in which of the above demonstrated ways). Therefore, you can access it as a method of bar
as well, usually by using this.doFooStuff()
.
Can a revealing prototype pattern extent another revealing prototype pattern
Am I missing anything?
Yes.
new function(proto) {
Do not use new
.
new base().eat (data);//This is just to show you can call the base. If needed.
Do not use new
. You'd create a new instance here, however what you want is get the eat
method from the base.prototype
and call
that on your Fish instance.
proto = new Animal()
Do not use new
!
Fish.prototype = (function(super) {
var proto = Object.create(super);
function eat(data) {
super.eat.call(this, data);
document.write("fish eating.<br>");
}
function swim(){
document.write("fish is swimming.<br>");
}
proto.constructor = Fish;
proto.eat = eat;
proto.swim = swim;
return proto;
})(Animal.prototype);
Revealing Prototype Pattern private variables
There is not a way to do that with the revealing prototype pattern.
You can only do that with something like this:
function MyClass() {
var v = 1;
this.getV = function() {
return v;
};
}
And that's why there are some die-hard enthusiasts for this kind of approach.
Personal option: Stick an underscore in front of it, and putting it on the object: this._v
. Don't fight JavaScript; use it.
Inheritance and module pattern
You're not using the module pattern in the correct way. Somehow, your "constructor" is called as an immediately-invoked function expression (IIFE), and the module closure is not. It should be the other way round.
Also, you can't assign to this.prototype
. To create the prototype object from which all instances will inherit, you will need to assign to the prototype
property of the constructor function (the this
keyword even pointed to the global window
object in your case).
And you should return the constructor function, not the prototype object, from the IIFE as soon as you have it.
Parent = (function () {
// constructor
function construct () {
console.log("Parent");
};
// public functions
construct.prototype.test = function () {
console.log("test parent");
};
construct.prototype.test2 = function () {
console.log("test2 parent");
};
return construct;
})();
Child = (function () {
// constructor
function construct() {
console.log("Child");
Parent.apply(this, arguments);
}
// make the prototype object inherit from the Parent's one
construct.prototype = Object.create(Parent.prototype);
// public functions
construct.prototype.test = function() {
console.log("test Child");
};
return construct;
})();
Revealing Module / Prototype Pattern
Although this code works as expected I red an article lately that this pattern uses large amount of memory if you have multiple instances
The code you presented in your first snippet is a singleton module, there are no "multiple instances". It is completely fine.
Only the thing that you titled Module pattern - Multiple instances
in your fiddle does suffer from memory disadvantages when it instantiates a very large amount of objects. However, notice that this is not a "module pattern" but the "factory pattern".
Now I'm wondering if it's faster / better for memory to use the Revealing Prototype Pattern?
In general, and if applied correctly, yes.
This benchmark surprised me, because the Module Pattern seems to be much faster. Is there any reason?
The code of their modules is messed up beyond all repair. I'm not even trying to comment on what is going on there.
Also I couldn't figure out how to have multiple instances with the Revealing Prototype Pattern
The benefit of the prototype is that its properties are shared amongst all instances. This means that the .init
method of all instances points to the same function, which has a single privateVar
in its revealing module scope - this variable exists only once for all instances! It's static, not instance-specific.
If you want to use the prototype, you cannot access truly private variables; you will need to use public properties. However, your clickFunction
needs a local (private) variable anyway for its closure, so there would be nothing wrong with not using the prototype here:
function Constructor( el ) {
var privateVar = $( el );
privateVar.on( 'click', function clickFunction() {
privateVar.addClass('click');
});
console.log( 'constructor: ' + privateVar.attr('id') );
}
Related Topics
How to Programmatically Click on an Element in JavaScript
How to Intercept Xmlhttprequests from a Greasemonkey Script
Linguistic Meaning of 'Let' Variable in Programming
How to Convert String into Float in JavaScript
Allow Only Numbers to Be Typed in a Textbox
Stop a Youtube Video with Jquery
Rails 4 - Gmaps4Rails - Map Won't Render
How to Read Console Logs of Wkwebview Programmatically
Jquery Clone() Not Cloning Event Bindings, Even with On()
Dynamically Loading a Typescript Class (Reflection for Typescript)
JavaScript Double Colon (Bind Operator)
JavaScript Call to Swift from Uiwebview
Setting Innerhtml VS. Setting Value with JavaScript
Why Does the Promise Constructor Need an Executor
Which Ecmascript 6 Features Imply Strict Mode