function Foo() {
this.SayFoo = function() {
console.log('Foo');
};
}
function Bar() {
this.SayBar = function() {
console.log('Bar');
};
}
Foo.prototype = new Bar();
var fooBar = new Foo();
fooBar.SayBar();
This obviously works, but is it the correct way to do it?
Is there any way to make use of jQuery's $.extend or something similar in order to achieve the same inheritance results?
Including other frameworks besides jQuery is not an option in this case.
There are actually multiple ways to do inheritance in JavaScript: neoclassical, prototypal, and functional. Douglas Crockford has nothing but bad things to say about neoclassical inheritance—the method you have above, and the method most Java/C# developers think will be the most natural. The reason revolves around all the awkward things you have to do to get it right—setting the prototype, setting the constructor, etc. Also, setting the prototype to a new instance of the parent class, like you have above, is usually frowned upon strongly, I believe because it complicates handling parameters with the base ctor.
If you're really sold on the neoclassical method, here's a great link that really goes over it.
The key part I reproduce for you here:
function Inherit(sub,super){
var thinF = function(){};
thinF.prototype = super.prototype;
sub.prototype = new thinF();
sub.prototype.constructor = sub;
sub.super = super.prototype;
if( super.prototype.constructor == Object.prototype.constructor ){
super.prototype.constructor = super;
}
}
FWIW Here's an example of functional inheritance that also highlights something you don't get with the neoclassical method: encapsulation/information hiding.
function eventRaiser(protectedStuff) {
protectedStuff = protectedStuff || {};
var that = {};
var events = {}; //private
protectedStuff.raise = function(key) {
if (!events[key]) return;
for (var i = 0; i < events[key].funcs.length; i++)
events[key].funcs[i].apply(null, Array.prototype.slice.call(arguments, 1));
};
that.subscribe = function(key, func) {
if (!events[key])
events[key] = { name: key, funcs: [] };
events[key].funcs.push(func);
};
return that;
}
function widget() {
var protectedStuff = {};
var that = eventRaiser(protectedStuff);
that.doSomething = function() {
alert("doing something");
protectedStuff.raise("doStuffEvent");
};
return that;
}
$(function() {
var w = widget();
w.subscribe("doStuffEvent", function(){ alert("I've been raised"); });
w.doSomething();
w.protectedStuff.raise("doStuffEvent"); //error!!!!! raise is protected
w.raise("doStuffEvent"); //and this obviously won't work
});
Yes, setting prototype to an instance is the correct way to do it.
Related
Just for the sake of curiosity, I was playing with prototypal inheritance and OOP inheritance in Javascript. Most results involve emulating 'Class' and 'extends' concepts with functions, while others use the prototype and constructors.
I wrote this code:
function Warrior(weaponName) {
var weapon = weaponName;
this.getWeapon = function() {
return weapon;
};
this.setWeapon = function(value) {
weapon = value;
};
this.displayInfo = function() {
return {
"weapon": this.getWeapon(),
};
};
}
function Archer() {
var accuracy = "86%";
this.parent = Archer.prototype; // Inheritance workaround
this.getAccuracy = function() {
return accuracy;
};
this.setAccuracy = function(value) {
accuracy = value;
};
this.displayInfo = function() {
var form = this.parent.displayInfo();
form.accuracy = this.getAccuracy();
return form;
};
}
Archer.prototype = new Warrior("bow");
var w = new Warrior("sword");
var a = new Archer();
console.log(w.displayInfo());
console.log(a.displayInfo());
I made this so when displaying the information from the Warrior class, it shows the object as
{ weapon: "sword" }
And when the information from Archer is shown, the object is:
{ weapon: "sword", accuracy: "86%" }
The "subclass" is taking information from the "superclass" and adding to it. Calling "getWeapon()" or "setWeapon" from Archer also works. The chain goes on without problems, even when I add a third class "Kyudoka" that extends "Archer" and has it's own properties as well.
But comparing to the more complex code I found while researching, I feel this could be a naive implementation (the "Inheritance workaround" line) and I'm missing something (considering that JS has a lot of subtlety).
This is a theorical question, I'm not using this code in any system.
There are mainly 3 kinds of inheritance in javascript, according to the book Javascript the Good Parts: Pseudoclassical, Prototypal and Functional.
The one you just posted would fit under the Pseudoclassical inheritance, where you emulate a Class behaviour using constructor functions.
I find more useful and flexible the Functional pattern, which allows you to protect your variables (make them private).
var constructor = function (spec, my) {
var that, other private instance variables;
my = my || {};
//Add shared variables and functions to my
that = a new object;
//Add privileged methods to that
return that;
}
Prototypal is basically having your objects inherit directly from other useful object, which would be something like having them (the useful objects) as your new object constructor prototype.
Object.beget = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
var a = {}
//Add shared variables to a
var b = Object.beget(a);
//Add new methods to b
That are many considerations to each of the patterns, for instance Crockford says in his book "The functional pattern has a great deal of flexibility. It requires less effort than the pseudoclassical pattern,
and gives us better encapsulation and information hiding and access to super methods.", but I've also seen articles arguing the other way around, such as this http://bolinfest.com/javascript/inheritance.php
EDIT ------
In case you might want to know different aproaches to reaching super methods, in the Functional pattern you can do the following:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function ( ) {
return method.apply(that, arguments);
};
});
var archer = function (spec, accuracy) {
var that = warrior(spec),
super_displayInfo = that.superior('displayInfo');
that.getAccuracy = function() {
return accuracy;
};
that.setAccuracy = function(value) {
accuracy = value;
};
that.displayInfo = function (n) {
var form = super_displayInfo()
form.accuracy = that.getAccuracy();
return form;
};
return that;
};
Put the functions on the prototype...
function Warrior(weaponName) {
this.weapon = weaponName;
}
Warrior.prototype = {
getWeapon : function() {
return this.weapon;
},
setWeapon : function(value) {
this.weapon = value;
},
displayInfo : function() {
return { "weapon" : this.getWeapon() };
}
};
//----------------------------------
function Archer(weaponName) {
Warrior.call(this, weaponName);
this.accuracy = "86%";
}
Archer.prototype = Object.create(Warrior.prototype);
Archer.prototype.constructor = Archer;
Archer.prototype.getAccuracy = function() {
return this.accuracy;
};
Archer.prototype.setAccuracy = function(value) {
this.accuracy = value;
};
Archer.prototype.displayInfo = function() {
return "weapon: " + this.getWeapon() + ", accuracy: " + this.getAccuracy();
};
//----------------------------------
var w = new Warrior("sword");
var a = new Archer("axe");
console.log(w.displayInfo()); // Object {weapon: "sword"}
console.log(a.displayInfo()); // weapon: axe, accuracy: 86%
Edit: fixed recursion
First of all, I took the animals example from the coffeescript site.
I want to simulate next things in javascript:
Classes
Public methods only
Private methods and variables only
Inheritance
Call methods from the super class
I think this way to create this is ok, but when I try to get the move method from the parent class, always it returns to itself. What I'm doing wrong?
BTW. Which are the best practices to achieve my goal? Is right what I'm doing?
var Animal = (function() {
function Animal() {}
var _private = {};
var _public = {
move: function() {
console.log('Can move');
}
};
Animal.prototype = _public;
Animal.prototype.constructor = Animal;
return Animal;
})();
var Snake = (function(_super) {
function Snake() {}
var _private = {};
var _public = {
move: function() {
console.log(Snake._super_.move);
console.log('Slithering');
}
};
Snake.prototype = _super.prototype;
Snake._super_ = _super.prototype;
for(var method in _public) {
if(Object.prototype.toString.call(_public[method]) === '[object Function]') {
Snake.prototype[method] = _public[method];
}
}
return Snake;
})(Animal);
var s = new Snake;
s.move();
This is very well written code in my opinion, with just one small mistake.
I think you got your pointers a little crossed, try this:
<script>
var Animal = (function () {
function Animal() { }
var _private = {};
var _public = {
move: function () {
console.log('Can move');
//this just returns a string to show which method was called
//inside of the child's move function's console.log
return "super move called";
}
};
Animal.prototype = _public;
Animal.prototype.constructor = Animal;
return Animal;
})();
var Snake = (function (_super) {
function Snake() { }
var _private = {};
var _public = {
move: function () {
console.log(Snake._super_.move());//Now we can call super's move
console.log('Slithering');
}
};
//This created the circular reference where Snake._super_ was pointing to
//Snake.prototype which was causing the error
//Snake.prototype = _super.prototype;
Snake._super_ = _super.prototype;
for (var method in _public) {
if (Object.prototype.toString.call(_public[method]) === '[object Function]') {
Snake.prototype[method] = _public[method];
}
}
return Snake;
})(Animal);
var s = new Snake;
s.move();//now this outputs "Can move", "super move called", "Slithering"
</script>
If you are asking for best practices, I'd say take any of ready to go solutions on the web. I prefer this one: http://canjs.us/#can_construct.
A few notices about your approach:
It's not reusable. You have to write the same code for every single class. At least you should extract for-loop to make this piece of code reusable.
You need to check _public.hasOwnProperty(method) to make your code more robust.
toString and valueOf methods require special handling since they are non-enumerable in IE<9.
Snake.prototype = _super.prototype; is a complete disaster. Since your super class will have all methods of child.
var F = function(){};
F.prototype = _super.prototype;
Snake.prototype = new F();
Snake.prototype.constructor = Snake;
Considering object creation patterns with private properties, one way to do is :
function MyStack (){
var list = [],
index = 0;
this.push = function(val){
return list[index++] = val;
};
this.pop = function(){// ...}
}
var stack1 = new MyStack(); stack1.push(5);
var stack2 = new MyStack(); stack2.push(11);
Problem with this: Every instance of Stack has it's own copy of methods 'push' and 'pop'.
Another way for implementing constructor method is:
function MyStack(){
this.list = [];
this.index = 0;
}
MyStack.prototype = {
insert: function(val){
return this.list[this.index++] = val;
},
pop:function(){//...}
}
Problem here: We lose the privacy of list and index.
Is there a way, such that we can have both methods reuse among instances and privacy of properties ?
I understand that we can have this for methods that don't operate on any state of the object, but I am talking more about those methods that do operate on the state.
Yes. I've edited this code so it's actually fully functional as you had intended it to work. It seems a bit redundant to me, but, it does provide you the ability to provide a public interface, but to keep your variables private and control the way the user interacts with them.
function MyStack(){
var list = [];
var index = 0;
this.getIndex = function(){
return index;
}
this.setIndex = function(val){
index = val;
}
this.list = function(val){
if(val){
// setter if a value was provided. Illustrating how you can control
// index, which I assume is the point of having these things private
// to begin with
return list[this.setIndex(this.getIndex() + 1)] = val;
}
// always return list - acts like a getter
return list;
}
}
MyStack.prototype = {
insert: function(val){
return this.list(val);
},
pop:function(){}
}
var stack1 = new MyStack();
stack1.insert(5);
var stack2 = new MyStack();
stack2.insert(11);
You should check out John Resig's Simple Javascript Inheritance. It is a great read, and it has been extended to provide support for privates, aptly called Privates.js;
A constructor function may return any object (not necesserily this). One could create a constructor function, that returns a proxy object, that contains proxy methods to the "real" methods of the "real" instance object. This may sound complicated, but it is not; here is a code snippet:
var MyClass = function() {
var instanceObj = this;
var proxyObj = {
myPublicMethod: function() {
return instanceObj.myPublicMethod.apply(instanceObj, arguments);
}
}
return proxyObj;
};
MyClass.prototype = {
_myPrivateMethod: function() {
...
},
myPublicMethod: function() {
...
}
};
The nice thing is that the proxy creation can be automated, if we define a convention for naming the protected methods. I created a little library that does exactly this: http://idya.github.com/oolib/
I think in both approaches you mentioned, When ever object is created using constructor pattern the properties will get copied to its objects. This you mentioned for the 1st approach as the concern. I feel the same will be applied for the second approach also along with your concern in this approach.
We generally go to the second approach you mentioned when ever we want to extend the properties of "MyStack" to some other class.
Lets say i want to extend your class MyStack to MyTest like below
var dummy = function();
dummy.prototype = MyStack.prototype;
var MyTest = function(){
};
MyTest.prototype = new dummy(); // Assigning MyStack properties to MyTest
var obj = new MyTest();
I'm having a little trouble working out how my JavaScript should be structured, etc..
My OOP skills in languages such as PHP, ActionScript 3 and so on are what I'm assuming to be on-par, but JS is lacking this which has thrown me off quite a bit in my learning.
I have a vague understanding of the prototype feature which I used a little in AS2 - I believe this is the closest I'll be able to get. At the moment, I'm laying out my code similar to this:
var slideshow =
{
property: value,
/**
* This is a method
*/
myMethod: function()
{
// do method things
}
};
// ------
slideshow.property ++;
slideshow.myMethod();
This all works okay, but it's void my ability to do something like:
var myslideshow1 = new Slideshow();
var myslideshow2 = new Slideshow();
myslideshow1.property = 10;
myslideshow2.property = 16;
I'm not sure on how to go about creating two different instances of one "object" I've created (in this case, slideshow).
I can't find any resources that explain the prototype feature in a way that makes sense.
Any pointers would be supoib.
Any javascript function can act as a constructor for a class, so try this:
function SlideShow(params) {
return {
property: value,
myMethod: function() {
//do method things
};
};
};
var slideshow1 = new SlideShow(params);
slideshow1.property = 10;
//etc.
I would frown apon using prototype to add methods to a class as there could be performance issues
Here is a sample class structure you could use. JavaScript classes are not much different the functions.
function MyItem(){
this.d = '';
this.clear = function( ) {
this.d = '';
}
}
var myItem = new MyItem( )
myItem.d = "test";
alert(myItem.d);
myItem.clear();
alert(myItem.d)
Some good reading here
You should avoid using the new operator, everything is public. A better way to do what you want to do, and have private variables and functions is to do the following:
var slideshow = function () {
var self = {};
var private_param = "hello";
var private_func = function(say) {
alert(say);
};
var method = function() {
private_func(private_param);
};
var param = 500;
self.method = method;
self.param = param;
return self;
// return object, with the method func and param param publicly accessible
// private_param and private_func are not accessible to the outside
};
var presentation = slideshow(); // new slideshow, you could edit to pass in init params
presentation.method(); // hello
Scenario 1 - everything works:
var AwesomeObject = function()
{
var self = this;
self.whatstuff = 'really awesome';
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns a new AwesomeObject
awesome.doStuff(); // prints 'i did really awesome stuff' on the console
Now i want it even awesomer:
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
return self;
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns the interal f object
awesome(); // prints 'i am awesome'
awesome.doStuff(); // throws an error
new AwesomeObject should return an executable function itself, so that i can say 'awesome();'
but i want it to inherit the AwesomeObject.prototype, too.
adding self.prototype = AwesomeObject.prototype; does not help.
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.prototype = AwesomeObject.prototype;
return self;
}
ok i can copy the AwesomeObject.prototype functions - one after the other - into the scope of f
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.doStuff = function() { AwesomeObject.prototype.doStuff.apply(self,arguments); }
return self;
}
but i think there must be a better way, a better pattern, what is it?
this issue drives me crazy, help would be really appreciated.
in general: how to create a function object that
can be created with new
returns a function object that can be executed
inherits all properties and methods of a given prototype
?
is there a way?
thx
Franz
A very simple pattern is a factory.
var AwesomeObject = (function() {
var AwesomeObject = function() {
this.whatstuff = 'really awesome';
};
AwesomeObject.prototype.doStuff = function() {
console.log('i did ' + this.whatstuff + ' stuff');
return this;
};
return function() {
var o = new AwesomeObject();
var f = function() { console.log("I am awesome"); };
for (var k in o) {
f[k] = o[k];
}
return f;
};
})();
var foo = AwesomeObject();
foo();
foo.doStuff();
Live Example.
The idea is that you seperate your function and your object into two things. Your object exists in the local scope of your function and the function can use the object.
The object itself inherits completely through the prototype.
The key is do forward all properties/methods of the object onto the function.
This is the cleanest solution.
When a property is resolved the prototype chain is traversed as you probably know.
But if you have an object awesome and try to evaluate awesome.doStuff, then awesome.prototype will never be queried for the property. You can verify this in your example, "doStuff" in awesome => false but "doStuff" in awesome.prototype => true.
So what you're doing is not changing the implicit properties of awesome, you are changing its prototype, meaning any objects created by doing new awesome will have that property. Verification: "doStuff" in new awesome() => true. And this makes sense, since there is no way to distinguish between a constructor or a regular function when using f/awesome.
The procedure when resolving a property p on an object o is roughly as follows:
Check whether p is defined on o
Check whether p is defined on o.__proto__ (usage of __proto__ is non-standard but widely implemented, except for jscript last time i checked and it has now been deprecated in SpiderMonkey)
Check whether p is defined on o.constructor.prototype
Check whether p is defined on o.constructor.prototype.prototype
etc
So one solution would be to simply set o.__proto__ = AwesomeClass.prototype. Think of __proto__ as a hidden intermediary object between an object and its prototype. Each instance receives its own unique __proto__ object. But this is deprecated and non-standard like I said.
We could also set the values in Function.prototype but that would override other Function properties and affect all Function instances. We don't want that.
So what's left? Not much it turns out. There is no way to set the complete prototype of an object while retaining it's inherited prototype. You will need to iterate through your prototype and copy all properties. Fortunately this will allow instanceof to behave as expected when working with chains of constructors, as well as allowing inheritance/overriding of properties properly.
The problem is really that there is no built-in way to copy the properties of an object into another one, and that there is no standard way to change an object's prototype chain ad-hoc (__proto__).
So use __proto__, or iterate through the prototype.
I don't think there is a good way to do this. I would redesign your program to avoid it.
However, here is a bad, platform-dependent solution (works on V8 using non-standard __proto__ property):
var PrototypeToBeInherited = {'inheritedProperty': 'inheritedPropertyValue'};
f = function() {
return "result";
};
f.__proto__ = PrototypeToBeInherited;
f()
=> "result";
f.inheritedProperty
=> "inheritedPropertyValue"
For your requirement that it must be created with "new", just wrap it in function:
F = function() {
return f;
}
var instance = new F();