I'm trying to practice JS OOP, particularly prototype inheritance, and I can't figure out why this JS Fiddle is returning undefined. Code below:
function Shape(name, edges) {
this.Name = name;
this.Edges = edges;
}
Shape.prototype.toString = function(){ return "Shape: " + this.Name;};
function Circle(radius) {
this.Radius = radius;
}
Circle.prototype.Area = function(){
return Math.PI * Math.pow(this.Radius, 2);
};
Circle.prototype = new Shape("Circle", 1);
Circle.prototype.constructor = Circle;
var circle = new Circle(5);
console.log(circle);
console.log(circle.toString());
console.log(circle.Area);
Could anyone shed some light on this please?
Executing your code, I get the following output:
Circle { Radius=5, Name="Circle", Edges=1 }
Shape: Circle
function()
So, there is no undefined here. However, I can imagine you wanted to see the calculated area be printed on the console instead of function().
This can be done by actually calling the Area function, like so:
console.log(circle.Area());
After making this modification (see JSFiddle), you get the correct result:
78.53981633974483
Explanation: In your implementation, you were only accessing the function object, which printed function(), instead of calling the function, which really calculates the desired value.
EDIT
As from your comment, I believe your question is a duplicate of this one. From the details given in this answer, I was able to get the following working:
function Circle(radius) {
this.Name = "Circle";
this.Edges = 1;
this.Radius = radius;
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
Circle.prototype.Area = function () {
return Math.PI * Math.pow(this.Radius, 2);
};
However, my JS skills are limited, so this might have a flaw or two. For more advanced inheritance, you may take a look at the accepted answer in the question I referenced above for hints on frameworks that would be worth using.
If you are calling Area function to get the area of circle then you need to call it like this
console.log(circle.Area())
JS Fiddle
None of your logs show undefined.
If you're testing in your developer's console, you'll find a final return value at the end of your input. This value is often undefined, and has nothing to do with your code.
I figured it out.
But its with thanks to everyone on this thread actually. It took a while for it dawn on me and its actually a rookie mistake.
I assigned the prototype function Area to object circle, before inheriting the base Shape prototype.
The section in question is now like so:
function Circle(radius) {
this.Radius = radius;
}
Circle.prototype = new Shape("Circle", 1);
Circle.prototype.constructor = Circle;
Circle.prototype.Area = function () {
return Math.PI * Math.pow(this.Radius, 2);
};
//creating the main Object variables with static Propertys
var MySystem={
Utility:{},
AppDbSystem:{
connecterObj:"",
objCollection:new Array(),
sendObjCollection:null,
phpGridCollection:null
},
OutManager:{},
DbIndex:{},
GoDb:{},
Ioform:{},
ListView:{},
WindowSystem:{},
AngularSystem:{
objCollection:null
}
}
//the parent class (top of the chain)
MySystem.GoDb.GoDb=function(){
var that=this;
this.namespace;
this.speicher;
this.initGoDb=function(table,group,indexArr,readOnly){
that.speicher=table;
}
this.showS=function(){
alert(that.speicher);
}
this.setNamespace=function(ns){
that.namespace=ns;
}
this.getNamespace=function(){
return that.namespace;
}
}
//ListView second Class of the Chain
MySystem.ListView.ListView=function(){
var that=this;
MySystem.GoDb.GoDb.apply(this); //IMPORTANT to make it as an Instance
this.initListView=function(submitIndex,idArr,methodActionArr){
that.initGoDb(submitIndex);
}
}
MySystem.ListView.ListView.prototype=new MySystem.GoDb.GoDb();
//The Child Class
MySystem.ListView.ListStandard=function(){
var that=this;
MySystem.ListView.ListView.apply(this);
this.init=function(elementYArr,attrs,methodActionArr,idArr,tableId,styleArr,styleArrTr,styleArrTd,withNumbers,submitIndex){
that.initListView(elementYArr);
}
}
MySystem.ListView.ListStandard.prototype=new MySystem.ListView.ListView();
//now use it
var test=new MySystem.ListView.ListStandard();
var test2=new MySystem.ListView.ListStandard();
test.init("eazy");
test.showS();
test2.init("second obj");
test2.showS();
test.showS();
Look at http://www.zipcon.net/~swhite/docs/computers/languages/object_oriented_JS/inheritance.html
And dont forget to do the apply call.
MySystem.ListView.ListView.apply(this);
Otherwise the Object propertys are static and not inheritable.
Related
I've been investigating multiple leveles of inheritance with "private" variable in each "class" in JavaScript, but run into this peculiar singularity:
function Ammo() {
var a = 0;
this.get_ammo = function() {
return a;
};
this.add_to_ammo = function() {
a = a+1
return a;
};
this.clean_ammo = function() {
return a=0;
}
}
function Weapon() {
var a =0;
}
function Gun() {
var a = 0;
this.fire = function(){
console.log("Bang");
}
}
Weapon.prototype = new Ammo();
Weapon.prototype.constructor = Weapon();
Gun.prototype = new Weapon();
Gun.prototype.constructor = Gun();
var a = new Ammo();
var w = new Weapon();
var g = new Gun();
a.add_to_ammo()
a.add_to_ammo()
a.add_to_ammo()
console.log(w.get_ammo())
// At this point I get 0, as expected. But after
w.add_to_ammo()
w.add_to_ammo()
w.add_to_ammo()
console.log(g.get_ammo())
// But here I get 3!
Can somebody explain why I get 3 after
console.log(g.get_ammo())
I thought that objects a, w, g are independent, so are their fields.
Also I found out that if I change
var a = 0;
to
this.a = 0;
I get expected result. fields of the object are unbound to their parents fields.
var a is defined in Ammo, but var a in the other constructors does absolutely nothing. The a that's being modified when you call the method no matter which instance is always the same a that was captured in the closure in Ammo.
You can't have private variables like you want in JavaScript, and that's ok. The most common way to do it is to make the variable public, and prefix it with an underscore, to mark it as "internal":
function Ammo() {
this._ammo = 0;
}
Then add the methods to the prototype and use this._ammo to reference that variable:
Ammo.prototype.getAmmo = function() {
return this._ammo
}
Then you can inherit with Object.create:
Weapon.prototype = Object.create(Ammo.prototype);
And in the constructor "call super":
function Weapon() {
Ammo.call(this) // gets own "_ammo"
}
Also, you are not setting up the constructor function properly. You should assign a function, not call it:
Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;
I don't have enough rep points to comment on #elclanrs answer, so forgive me.
His answer is all correct, but the most pertinent piece of information is the last
Also, you are not setting up the constructor function properly. You should assign a function, not call it:
Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;
your variables that are declared inside the scope of the function closure ARE IN FACT PRIVATE! however, you never properly instantiated you subclass objects, so you had a frankenstein thing going on: one object, lots of body parts.
Other than that there is nothing inherently wrong with your code, it's just not the way people usually write "Classes" and I won't explain why in the context of this question.
I Get an 'undefined' error when trying to run the following code. It happens on the line this.xPositionForPageAtIndex(selectedPageNumber). When I try to log this all of the instance properties are there, except the function.
function Gallery(div) {
this.count = 5;
this.pageWidth = 500;
this.selectedPage = 1;
this.xPositionForPageAtIndex = function(pageIndex) {
if (pageIndex < 1 || pageIndex > this.count) {
return 0.0;
}
return (pageIndex - 1) * this.pageWidth;
}
}
Gallery.prototype = {
set selectedPage(selectedPageNumber) {
var page = this.pages[((selectedPageNumber) + 1)];
if (!page.classList.contains("animate")) {
page.classList.add("animate");
}
if (!page.classList.contains("final")) {
page.classList.add("final");
}
console.log(this);
this.binder.setAttribute("-webkit-transform", "translateX(" -this.xPositionForPageAtIndex(selectedPageNumber) + "px)");
this.selectedPage = page;
}
}
I am a little new to Javascript OOP, but I don't think I really know enough terminology to be able to properly research this answer.
Concat issue
On the line you said you were having trouble with had a minus instead of a plus:
"translateX(" -this.xPositionForPageAtIndex(selectedPageNumber)
should be
"translateX(" + this.xPositionForPageAtIndex(selectedPageNumber)
Optimize by putting public methods in the prototype
Also, it may be a good idea to put xPositionForPageAtIndex in the prototype as well, since it doesn't rely on any private fields. Any public function(which means it relies on no private fields) can go into the prototype. That way, there won't be a copy of the function for each instance of the object you're creating.
Based on your code, I don't think you'll have enough Gallery instances for this to be a problem, but it's good practice nonetheless.
On the other hand, if your function relies on some sort of private field, that means it's a privileged function, and it cannot go into the prototype. Something like this:
function Gallery(someParam){
//this is a private variable
var hiddenVar = someParam + "bar";
// this is a privileged method: publicly accessible, but
// can "see" private variables
this.showHidden = function() {
return hiddenVar
};
};
var gal = new Gallery("foo");
gal.hiddenVar; // undefined
gal.showHidden(); // "foobar"
Unintended infinite recursion
A bigger problem is the following line:
this.selectedPage = page;
that line is within the setter for the property selectedPage.
That line makes selectedPage recursively call itself, and can only end in a RangeError.
Writing it in terms of functions makes it a little more clear, so here is what's happening:
var a = {
foo: function(param){
// do some stuff
this.foo(4);
}
};
calling a.foo(2) will result in a RangeError.
It's hidden a bit, because of the way ES5 setters work. Here's what that would look like using setters:
var a = {
set foo(){
// do some stuff
this.foo = 3;
}
};
calling a.foo = 2 will result in a RangeError because the setter function is being called recursively.
Hope that helps a bit. If you haven't checked out Douglas Crockford yet, youtube him. There are some good lectures that may help you out quite a bit.
I was reading Crockford's tutorial http://javascript.crockford.com/private.html.
private variables are implemented by function inside constructor that makes possible to associate private variables to closure.
Generally javascript libraries are open, so anyone can see and modify the private variables by modifying the inner function of constructor thru instances/objects. like this:
c1.radius = function (){return 500;};
Be more precisly: In real OOPS no one can modify private variable by objects but here we can.
Can anyone please suggest me the way to make it full tamper proof like JAVA or C?
function Circle(radius) {
this.radius = function(){ return radius;}
}
Circle.prototype = {
constructor: Circle,
area: function(){
return (Math.PI)* (Math.pow(this.radius(),2));
}
};
c1 = new Circle(5);
console.log(c1.radius());
console.log(c1.area());
c1.radius = function (){return 500;};
1st off, don't worry too much about making it tamper proof. If somebody really wants to, they'll be able to access what they want.
2ndly, you can't really do this unless you're using ECMAScript 5 (IE9+, Safari 5+, Chrome 7+, FF 4+). If you're using an ES5 browser, you can do what you want using the Object.defineProperty method, or using Object.create:
function Circle(radius) {
Object.defineProperty(this, 'radius', {
value: radius
});
}
NOTE: When using Object.create or Object.defineProperty, properties are by default non-writable, non-configurable (type can't be changed and property can't be deleted), and non-enumerable (won't show up in for(var x in obj) constructs).
What about this?
function oTest(){
var a; // "private"
this.b; // "public"
this.get_a = function(){
return a
)
}
var aTest = new oTest();
aTest.private_get = function(){
return a
}
aTest.private_get() // ReferenceError: a is not defined
aTest.get_a() // works
I'm not sure I fully understand your question, but a is only available to the original set of methods provided.
You might want to look at traits.js. In the following example radius and area are immutable or tamper proof.
function TCircle(radius) {
return Trait.create(
Object.prototype,
Trait({
radius: radius,
area: function() {
return (Math.PI) * (Math.pow(this.radius, 2));
}
}));
}
var circle = TCircle(5);
console.log(circle.area()); // 78.53981633974483
circle.radius = null;
console.log(circle.area()); // 78.53981633974483
circle.radius = 99;
console.log(circle.area()); // 78.53981633974483
If you want a mutable object then you would use Object.create rather than Trait.create above.
One way to define a class in Javascript is with closures and the object literal. As an example, consider a circle:
var circle = function(radius) {
var radius = radius;
return {
area: function() {
return Math.PI*(radius*radius);
}
}
}
Circle objects can then be instantiated with the internal variables remaining encapsulated:
c = circle(1);
c.area(); // Returns pi
c.radius; // Returns undefined
Unfortunately with this method, if I was to create multiple circles the area function would be copied for each instance. This is where the prototyping is usually used:
var Circle = function(radius) {
this.radius = radius;
}
Circle.prototype.area = function() {
return Math.PI*(this.radius*this.radius);
};
Now the problem is that variables cannot be declared private:
c = new Circle(1);
c.area(); // Returns pi
c.radius; // Returns 1
Does anyone know how I would get the best of both? Efficiency is an issue so would rather avoid the current formulation of the first method, and I am writing for a public API so don't want users to have access to internal variables/methods. Thanks in advance...
How about this:
function Circle(radius) {
this.getRadius = function() { return radius; }
}
Circle.prototype.area = function() {
var r = this.getRadius();
return Math.PI * r * r;
};
Now each instance of the Circle pseudo-class has two methods:
area which is inherited from the prototype thus making it a public method
getRadius which is assigned to the instance object thus making it an instance method
The radius value is still retrievable via getRadius though. However, if getRadius could determine whether it's called from within a Circle.prototype method and only return the radius value if it is, then that would solve it, but I'm not sure that that can be done.
This is what I came up with, though whether creating the GetArea() method everytime is "efficient" I doubt, but it's the only way I'm aware of to access the a local scope variable from prototype methods:
var Circle = (function(){
var Circle = function(radius) {
this.GetRadius = function(){
return radius;
}
};
Circle.prototype.area = function() {
var rad = this.GetRadius();
return Math.PI*(rad*rad);
};
return function(radius){
return new Circle(radius);
}
})();
(This will allow access to the value of the Radius of the circle, but not allow you to change it, which is why I presume you wanted this)
I am involved in a web application project at the moment and we are not going to be using a framework.
I am looking for the 'best' javascript inheritance implementation. I have worked with prototypal style classes as follows:
function animal(options) {
self = this;
//properties
this.name = options.name;
//events
this.onXYZ = options.onXYZ;
//event handlers
this.handlerOfEvent = function() {
//do something using 'self' as the 'this' variable
}
}
animal.prototype.aFunction = function()
{
//do something
}
etc.
I have not used inheritance without a framework (usually use Mootools) but I do understand to a point how it works in Javascript and have seen a fair few implementations.
I wanted to get some feedback on where I could find the best implementation, one that doesn't fiddle with any native types and allows me full access to the ascendant classes' properties and functions.
Any pointers would be greatly appreciated.
Thanks very much for your time.
There's a method described by (who else) Douglas Crockford that I've been partial to as of late:
var rectangle = function(width, height)
{
var h = height, w = width;
var scale = function(s)
{
h = h * s;
w = w * s;
}
return { scale: scale };
}
var square = function(width)
{
var o = rectangle(width, width)
// Add things to o, if needed
return o;
}
Not a terribly good example, as nothing is really being extended, but it should get the idea across. In order to instantiate these objects, simply use this:
var newRectangle = rectangle(3, 4); // 3 by 4 rectangle
var newSquare = square(6); // 6 by 6 square
I tried many approaches in the past. I like John Resig way of implementation the most. It's very simple. You can see full example and javascript file (only around 25 lines of code) from http://ejohn.org/blog/simple-javascript-inheritance/
Just to complete the answer, you can implement a class like this after include his code..
var Person = Class.extend({
name : '',
init : function (name) {
this.name = name;
},
say : function () {
alert("I'm " + this.name);
}
});
var mick = new Person("Mick");
mick.say();
Take a look at Simple Javascript Class Project (constant, property, protected, static, utils, and more), Simple JavaScript Inheritance and Inheritance Patterns in JavaScript.
Simple Javascript Class (sjsClass) Example
Class.extend('Foo', {
__protected : {
privV : 123,
privF : function () {
return this.privV + this.priv3;
}
},
'protected priv3' : 'Protected Value',
setX : function (x) {
this.privV = x;
},
test : function () { return this.privF(); }
});
var f = new Foo;
f.setX(456);
f.test(); // -> 'Protected Value456'
f.privF(); // -> Error
f.privV; // -> undefined
f.priv3; // -> undefined
You should check the videos from Douglas Crockford about "parasatic inheritance".
Here's a basic example
var pkg={};//simulating a package
pkg.ObjA=function (){
var privateField;//every inner function will have a closure to this field, this is the way to simulate private fields
var privatefunc=function(){
//same for private functions
};
//use object augmentation to add different fields to the "that" reference
that.publicMethod=function(){
//do something
};
return that;
}
//create two different instance of the object A
var instance1=pkg.ObjA();
var instance2=pkg.ObjA();
pkg.ObjB=function(){
//the that of this object is based on the ObjA
var that=pkg.ObjA();
//specialize the that to simulate inheritance
that.newMethod=function(){
}
return that;
}
var child=pkg.ObjB();