Replacing __proto__ with prototype - javascript

I tend to write my Javascript "classes" in c-style.
In C# (for example) we do this
public class Parent {
// stuff
}
public class Child : Parent {
// Protected and public stuff from Parent will be accessible
}
In JS I found the equivalent of this by using proto, in example
var namespace = namespace || {};
namespace.Parent = function() {
// Public variables
self.pubVariable = "I am accessible";
// Private variables
var priVariable = "I'm not accessible outside of self";
// ctor
function self() {}
return self;
}
namespace.Child = (function() {
this.__proto__ = new namespace.Parent();
// ctor
function self() {}
self.init = function() {
// Prints the pubVariable
console.log(pubVariable);
};
return self;
})($);
// Call it (statically)
namespace.Child.init();
While this works it is Webkit and Mozilla only. I've understood that this could somehow be achievable using prototype but can't figure out how. Any advice is appreciated. Thanks!

For parent/child classes, I would do something like this
// your parent class
var Parent = function() {
// parent constructor
console.log("parent constructor!");
// some public properties
this.foo = "foo";
this.bar = "bar";
// a private data member
var secret = "123456";
};
// a parent function
Parent.prototype.something = function() {
console.log("something!");
}
// your child class
var Child = function() {
// call parent constructor
Parent.call(this);
// child constructor
console.log("child constructor!");
// override bar
this.bar = "override!";
};
// the magic!
// child prototype build from parent prototype
Child.prototype = Object.create(Parent.prototype, {constructor: {value: Child}});
Example usage
var c = new Child();
c.something();
// => parent constructor!
// => child constructor!
// => something!
c.foo //=> "foo"
c.bar //=> "override!"
If you're using "namespacing" the concept is identical.
EDIT
Per your comment, here's and added demonstration
var Foo = function(){};
Foo.prototype.hello = function(){ return "hello!"; };
var foo = new Foo();
// call our hello method
// this calls foo.__proto__.hello
foo.hello(); //=> "hello!"
// override `hello` method for this instance
foo.hello = function(){ return "こんにちは"; };
// call our hello method again
// this calls foo.hello because it is defined directly on our instance
// (it has a higher precedence in the lookup chain)
foo.hello(); //=> "こんにちは"
// remove the override
delete foo.hello;
// call our hello method again
// this goes back to calling foo.__proto__.hello
foo.hello(); //=> "hello!"
// remove the method prototype
delete Foo.prototype.hello
// call our hello method one last time
// spoiler: it's gone!
foo.hello(); //=> TypeError: Object [object Object] has no method 'hello'
As you can see, you lose this functionality by directly defining methods on the instance using this.something = function(){};. I personally prefer defining methods on the prototype because of the added flexibility. This way, the prototype really works like a blueprint. You get all the pre-defined behavior; you can modify if necessary and revert to the original whenever you want, all on a per-instance basis.
ONE MORE THING
In our last example, we had a prototype method and an instance method override. Is there a way to call the original method too? Let's see!
var Foo = function(){};
Foo.prototype.hello = function(){ return "hello!"; };
var foo = new Foo();
foo.hello = function(){ return "こんにちは!"; }
// call override method
foo.hello(); //=> "こんにちは!"
// call original method
Foo.prototype.hello.call(foo); //=> "hello!"
// japanese just one more time...
foo.hello(); //=> "こんにちは!"
This would work too, but I never really have the need. I suppose the benefit is you don't need to know the original class this way :)
// call original method from the instance
foo.__proto__.hello.call(foo); //=> "hello!"
PROTOTYPES!

I think, you want this
// namespace
var namespace = namespace || {};
// Parent Class
namespace.Parent = function() {
this.pubVariable = "I am accessible";
var priVariable = "I'm not accessible outside of this";
}
// Child class
namespace.Child = function() {
// namespace.Parent.call(this);
this.init = function()
{
// returns Parent class' pubVariable
// inherited by namespace.Child.prototype
return this.pubVariable;
}
};
// inherit Parent class
namespace.Child.prototype = new namespace.Parent();
var kid = new namespace.Child();
console.log(kid.init()); // I am accessible
If you use namespace.Parent.call(this) then Child class will have it's own copy of pubVariable but now Child class is using Parent's pubVariable.
Also, if you want to share methods from parent class with sub classes then you should add methods in the parent class' prototype, like this
namespace.Parent = function() { //... }
namespace.Parent.prototype.aMethodInParent = function(){ //... };
So, when you will inherit it in a subclass like this
namespace.Child = function() { // ... };
namespace.Child.prototype = new namespace.Parent();
Another Sub/Child Class
namespace.AnotherChild = function() { // ... };
namespace.AnotherChild.prototype = new namespace.Parent();
In this case both sub/child classes will use the same aMethodInParent() method from their parent class.
DEMO.

Related

How to set the constructor of an Object without changing to a new Object?

In this related question, the answer for setting a constructor is like so:
function OldClass() {
alert("old class with incomplete constructor")
}
function ChangedClass(){
alert('new class with same prototype and more complete constructor');
}
ChangedClass.prototype = OldClass.prototype;
var theClassIWant = new ChangedClass();
This is not really setting the constructor, it's making a new object and inheriting the prototype. How can I set the constructor of an Object without changing to a new Object? Is it possible?
P.S. I want something like this:
//non working code
var Foo = function() {}
Foo.prototype.constructor = function(bar_val) {
this.bar = bar_val;
}
var fez = new Foo("cat")
console.log(fez.bar); // outputs: cat;
constructor is a property of the constructor function's prototype, which points to the function itself by default.
When you modify Foo.prototype.constructor, this property points to another function. However, the constructor function Foo remains. So when you create an object, you are still instantiate the constructor function Foo, not the one Foo.prototype.constructor points to.
This is why your code doesn't work. Then let's talk why we need to change the constructor and how to.
In ES5 and before, we take advantage of prototype to simulate a class inheritance mechanism. Which looks like this:
// parent class
function Person(name) {
this.name = name
}
// define parent method
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent properties
this.job = 'Coding'
this.major = major
}
// inherits properties and methods from parent prototype
Coder.prototype = new Person()
// define child method
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
// instantiate a child object
var me = new Coder('Leo', 'JavaScript')
console.log(me) // {name: "Leo", job: "Coding", major: "JavaScript"}
Everything looks perfect, but there a problem:
console.log(me.constructor) // Person
What? Isn't me constructed with Coder? Why?
Go back to the first line of this answer, read it again: constructor is a property of the constructor function's prototype.
Originally Coder.prototype.constructor is Coder itself. But with this line: Coder.prototype = new Person(), it got changed. Coder.prototype.constructor now equals Person.prototype.constructor, which is Person.
Well, some would say, try instanceof. Yes, that works:
me instanceof Coder // true
But it's also true for Person, because Coder is a sub class of it:
me instanceof Person // true
This doesn't make sense so we need to fix the constructor problem. That's why we use Coder.prototype.constructor = Coder after Coder.prototype = new Person(), to get back the original constructor.
Full code looks like this:
// parent class
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent class
this.job = 'Coding'
this.major = major
}
Coder.prototype = new Person() // inherits parent's prototype
Coder.prototype.constructor = Coder // get back constructor
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
myClass = {
constructor: function(text){
console.log(text);
}
}
let ob = Object.create(myClass);
ob.constructor("old constructor "); //Output: old constructor
myClass.constructor = function(){
console.log("new constructor ")
}
ob.constructor(); //Output: new constructor
You can do this with every property or function of a class.
Watch this Video here. It explains it perfectly.

JS Inheritance: calling the parent's function from within the child's function

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;
};

Node JS: Accessing inherited function in subclass's function

Let's say I have two classes, Base and Child. Base is the base class that Child will be inheriting from. Here's the code to visualize this:
Base.js
function Base(init) {
}
function log() {
console.log('here');
}
Base.prototype.log = log;
module.exports = Base;
Child.js
var Base = require('../Base.js');
var Child = module.exports = function Child(init) {
Base.call(this, init);
};
require('util').inherits(Child, Base);
function test() {
this.log(); // doesn't work
Base.prototype.log(); // Works but is quite ugly
Child.super_.prototype.log(); // Works but is even uglier
}
Child.prototype.test = test;
What I would absolutely love to do is something like this.log() or even log() would be nice. I realize I can set a variable to that in my inherited class, but then I would have to do that for every class that inherits Base, which is definitely not ideal. So my question is, can I do something like this.log() without having to set a variable in the inherited class? Am I misunderstanding something?
Updated Answer:
From your comment below, replying to my statment that this.log() should work:
Well, so that's the thing. When I'm in Child's test function, this is an empty object, so I'm assuming somewhere down the line I'm not getting the proper scope.
You haven't shown how you're calling test, but I suspect that's where the problem is. Provided you call it via a Child instance:
var c = new Child();
c.test();
...then within the call, this will be the child instance, which will inherit (indirectly) the Parent.prototype object with its log property.
But how you call it is important. This wouldn't work, for instance:
var c = new Child();
var f = c.test;
f();
If you do that, within the call to the function, this will be the global object (or undefined if you're in strict mode), not a Child instance. This is because in JavaScript, this is set primarily by how a function is called, and calling it like that doesn't set this to what you want.
This matters for callbacks, because passing in c.test as a callback:
someFunctionThatUsesACallback(c.test);
...means the code calling back won't set this for you.
If you need to do that, Function#bind will help:
var f = c.test.bind(c); // Returns a version of c.test that, when called,
// will have `this` set to `c`
f(); // Works, `this` is the `Child` instance
And similarly:
someFunctionThatUsesACallback(c.test.bind(c));
More (on my blog):
Mythical methods
You must remember this
Original Answer:
If you set up the prototype hierarchy correctly, and Child.prototype doesn't have log on it (and you don't put a log property on instances), then you should be able to use this.log(); just fine. If you can't, then the hierarchy hasn't been set up correctly.
I don't know what util.inherits does, but setting up the relationship between Child and Parent correctly isn't complicated:
function Parent() {
}
Parent.prototype.log = function() {
console.log("log called");
};
function Child () {
Parent.call(this);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // This line is largely optional, but a good idea
// Usage
var c = new Child();
c.log(); // "log called"
But if you override log in your Child.prototype or assign a log property to instances, and you want to use Parent's version of log, then of course you can't just use this.log() because the property doesn't refer to Parent.prototype.log anymore.
When you need to call the parent version of something (I call them "supercalls," and I don't think that's original), you have to do more work:
I usually set up hierarchies like this by passing the parent constructor into a function I use to build the child, e.g.:
var Child = (function(Super) {
var pp = Super.prototype;
function Child() {
}
Child.prototype = Object.create(pp);
Child.prototype.doSomething = function() {
// Call `log` with appropriate `this`
pp.log.call(this);
};
return Child;
})(Parent);
By always using that pattern, I avoid having to write Parent inside the Child code (I use the Super arg instead), so if I need to rebase Child, I just change what I pass into the function.
Because that's fairly ugly (for instance, it's unclear at the top of Child that it derives from Parent, since Parent is at the bottom) and involves boilerplate code I don't feel the need to write again every time, I wrote a simple helper script for it I call Lineage, which makes it look like this:
var Child = Lineage.define(Parent, function(p, pp) {
p.doSomething = function() {
// Call `log` with appropriate `this`
pp.log.call(this);
};
});
Note that Lineage passes in both the Child and Parent prototypes as arguments, making it concise to use them (and since you get to pick those argumetn names, you can use whatever terminology works for you — I use p for the prototype of the "class" being created [Child in the above], and pp for the parent's prototype, etc.).
The standard inherits function from node.js is (in my humble opinion) very bad code. Instead I prefer to use augment to create classes:
// base.js
var augment = require("augment");
var Base = module.exports = augment(Object, function () {
this.constructor = function (init) {
};
this.log = function () {
console.log("here");
};
});
// child.js
var augment = require("augment");
var Base = require("./base");
var Child = module.exports = augment(Base, function (base) {
this.constructor = function (init) {
base.constructor.call(this, init);
};
this.test = function () {
this.log();
};
});
In addition augment.js is just 20 lines of code and can be used everywhere.
Just as an FYI, I ended up putting this in the global variable that Node creates for you. I realize that's bad practice, but it's a logging mechanism that needs to be used by any class, controller, etc., so I don't think it's that terrible of a solution.
However, in Compound, you can create no_eval controllers, which means they look like typical prototypical functions... so you can essentially create a mixin, or I can require my mixin and use it like a class... like this:
var ControllerMixin = require(process.cwd() + 'app/mixins/ControllerMixin.js');
var Log;
var LoggerController = module.exports = function LoggerController(init) {
ControllerMixin.call(this, init); // mixin approach
Log = require(process.cwd() + 'app/utils/LoggerMixin.js')(init); // class approach
};
LoggerController.prototype.index = function index(controller) {
controller.logMessage('blah'); // using mixin
Log.logError('hi'); // using class
global.logWarning('yep'); // global approach
return controller.send({success: true});
};
So there are options... just have to find what you think is the best approach.
Every answer I see online either looks complicated, or relies on external libraries. Why not just boil down to the basics, assuming you use a custom type design pattern, which is very similar to traditional OOP.
parent.js
//the main parent class
// class Parent
module.exports = Parent;
function Parent(a) {
if (!(this instanceof Parent)) {
return new Parent(a);
}
this.a = a; //Some parent variable
}
Parent.prototype = {
// Instantiate child:
getChild: function() {
var Child = require('./child');
return new Child(this);
},
// Some parent function, print some text:
printText: function(text) {
console.log(text);
}
};
child.js
//Similar to class Child extends Parent
module.exports = Child;
function Child(parent) {
this.parent = parent;
}
Child.prototype = {
// Prints Parent Variable:
printParentVariable: function() {
console.log(this.parent.a);
},
// Calls Parent Function:
callParentFunction: function() {
this.parent.printText('Child calling parent function.');
}
};
test.js
var parent = require('./parent')('parent text'); //instantiate parent with some text
var child = parent.getChild(); //create instance of a child
//*** Child has full access to its parents variables and methods ***//
console.log(child.parent.a); //Print the parent text "parent text"
child.printParentVariable(); //Child method which prints the parent variable "parent text", identical to line above.
child.parent.printText('Child calling parent'); //Call parent method, to print provided text
child.callParentFunction(); //Calls parent method, identical to above.

Prototype for private sub-methods

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.

javascript inheritance with protected variables

Is it possible in javascript to have a variable that is not able to access out side the class's functions, but is able to be accessed by classes that inherit it? I.E:
class1 has protected var x = 4;
class2 inherits class1;
class2.prototype.getVar = function(){return /* parent, uber, super, whatever */ this.x;};
var cl2 = new class2();
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
No. Prototypal inheritance is limited to properties of objects.
Variables within the constructor are only available to other code in that variable scope.
You could probably come up with something like...
function cls1() {
var a = 'foo';
this.some_func = function() {
alert(a);
};
}
function cls2() {
cls1.apply(this, arguments);
var cls1_func = this.some_func;
var b = 'bar'
this.some_func = function() {
cls1_func.apply(this, arguments);
alert(b);
};
}
var x = new cls2;
x.some_func(); // alert "foo" alert "bar"
Or to make it more specific to your pseudo code...
function class1() {
var x = 4;
this.getVar = function() {
return x;
};
}
function class2() {
class1.apply(this, arguments);
var cls1_get_var = this.getVar;
this.getVar = function() {
return cls1_get_var.apply(this, arguments);
};
}
class2.prototype = Object.create( class1.prototype );
var cl2 = new class2;
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
I think you need to use a closure to achieve what your trying to do. Something like this:
Class1 = function() {
var x = 4;
return {
getVar: function() {
return x;
}
}
} ();// executes the function immediately and returns an
//an object with one method - getVar. Through closure this method
//still has access to the variable x
Class2 = function() { };// define a constructor function
Class2.prototype = Class1;//have it inherit from Class1
Cl2 = new Class2();//instantiate a new instance of Class2
console.log(Cl2.x);//this is undefined
console.log(Cl2.getVar());//this outputs 4
This is one of the neat things about javascript in that you can achieve the same things in javascript as you would in a class based language without all the extra key words. Douglas Crockford (always good to consult about javascript) explains prototypal inheritance here
Edit:
Just had a second look at your question.If you want newly created methods in your class to access the variable in the base class then you would have to call the getVar method within your own method.Like such:
Class2 = function() {
this.getVar2 = function() {
return this.getVar();
}
};
console.log(Cl2.getVar2()) //outputs 4

Categories