Nesting of classes and this value in JavaScript - javascript

Can I write nested classes in Javascript?
function A()
{
this.a;
this.B = function()
{
this.ab ;
this.C = function()
{
this.ab = 0;
}
}
}
If the above code is correct,then
1.How do I declare an object of type B
2.Whose property is ab.A() 's or B() 's?.
3.Inside B() where does the 'this' points to.To A() Or to B()?

In your example, the "classes" will be instance-specific. Are you sure you want that? You might be looking for something more along the lines of:
function A() {
// ...
}
A.B = function() {
// ...
};
var one = new A();
var two = new A.B();
Although the "nested" classes won't be able to access "private members" because JavaScript doesn't have those in the first place.
As for your example:
You would create an instance of A, say new A(), and access B, say new new A().B()1, or replacing new A() with a variable.
Neither, it's an empty statement for now... but it would be a property of the B instance.
To an instance of B (unless Function.call or Function.apply is used).
1 Yes, it works!

Abstract:
Calling to function without using new operator means that this will be refer to object in which that function was created.
For global variables this object is window object.
Calling using new - function behave as constructor like in classes and this refers to this instance which will been created
1.How do I declare an object of type B
First way( as a curiosity ) - by calling to A without using new operator this will be refer to windowobject and B method and all other what was declared with this leaks to global scope because A == window.A => true
A();
var b = new B; // means => new window.B //parentheses can be ommited if you invoking without arguments
alert( ab ) // alerts 'inside A' -> value from code presented below
or from instance of A:
new new A().B // means => new ( new A ).B
Be careful.
2.Whose property is ab.A() 's or B() 's?.
As above, it depends of how we'll accessing to it:
function A()
{
this.ab = "inside A";
this.B = function()
{
this.ab = "inside B";
this.c = function()
{
this.ab = "inside C";
}
}
};
Check this out
var a = new A;
a.ab // "inside A"
a.B(); // in B now 'this' refers to 'a', 'a.ab' will be replaced to 'ab' from inside 'B'
a.ab // "inside B"
but
var a = new A;
a.ab // "inside A"
var b = new a.B;
a.ab // "inside A"
b.ab // "inside B"
// and now
b.c()
b.ab // "inside C" and so on:)
3.Inside B() where does the 'this' points to.To A() Or to B()?
As above:)

It's very unorthodox, but there's nothing stopping you from nesting constructor functions in JavaScript.
From your example, you can access the B function from an instance of A:
var someA = new A();
var someB = new someA.B();
To answer your other question:
this.B = function() {
this.ab = 0;
this.c = function() {
this.ab++;
}
}
What this refers to inside of B depends on how B is invoked. If you call B as a constructor, with the new keyword, this will be a new object inheriting from B's prototype.
If you call B without new, it will be treated as a method, and this will be the instance of A on which the method was called.
And so on with C. If C is called with new, this inside of C will be a new object inheriting from C's prototype. Or C can be a method of B, which makes a lot more sense. Is something like this what you're wanting:
function A() {
this.a;
this.B = function() {
this.ab = 0;
this.c = function() {
this.ab++;
}
}
}
var someA = new A();
var someB = new someA.B();
console.log(someB.ab); //0
someB.c();
console.log(someB.ab); //1
DEMO
Finally, note that, though nesting constructors like this isn't too common, there's nothing stopping you from adding to B's prototype just like you would any other constructor
function A() {
this.a;
this.B = function() {
this.ab = 0;
this.c = function() {
this.ab++;
}
}
this.B.prototype.foo = function() { alert("Bar " + this.ab) };
}
var someA = new A();
var someB = new someA.B();
console.log(someB.ab);
someB.c();
console.log(someB.ab);
someB.foo(); //Bar 1
Updated Demo

Related

Get the calling object of an instanced constructor?

I'm not sure if the title did this justice, but here is what I have...
function A() {};
A.prototype.B = function(){
this.backref = //?? -- should be set to "a"
};
var a = new A(); // specialized factory...
var b = new a.B(); // instantiate an "a" specialized version of B
var zztop = b.backref instanceof A; //would be true
I need to assign backref to the instance "a" that called the B constructor. How can I do this? I've looked through all the properties in Chrome debugger, and am not even sure it is possible. Anyone know how to do this? I need to do this because I need access to variables stored in "a". Or is there a better way to do something similar?
I'm not sure if there's a way to do this just using the properties given to you, but you can always make the backref one of the arguments to the B constructor:
A.prototype.B = function(backref) {
this.backref = backref;
}
var a = new A();
var b = new a.B(a);
Ugly, but it works.
What you are describing is called inheritance. You want object B to inherit the properties of object A.
function A() {
this.length = 3;
}
function B() {
this.height = 5;
}
B.prototype = new A();
B.prototype.constructor = B;
var obj = new B();
obj.height; // returns 5
obj.length; // returns 3
Here's a jsFiddle: http://jsfiddle.net/d6QeT/

JavaScript inheritance with unexpected behaviour

I don't know how to solve the following JavaScript problem:
function A() {
var numbers = [];
this.addNumber = function(number) {
numbers.push(number);
}
this.getNumbers = function() {
return numbers;
}
}
A.prototype.alertNumbers = function() {
var numbers = this.getNumbers();
var length = numbers.length;
var number;
var numbersString = "";
for (var i = 0; i < length; i++) {
number = numbers[i];
numbersString += " " + number;
}
alert(numbersString);
}
B.prototype = new A();
function B() {
this.addNumber(1);
this.addNumber(2);
}
var b = new B();
b.alertNumbers();
var otherB = new B();
otherB.alertNumbers();
The working code is here: http://jsfiddle.net/pFxse/
I'm expecting that otherB.alertNumbers(); also shows "1 2" and not "1 2 1 2".
Thanks
The problem is that when you do:
B.prototype = new A();
You set B.prototype to be an instance of A, thus B.prototype will have 2 functions that access a private variable numbers.
Now when you access (new B()).addNumber(), you will use the function from the prototype and thus the array from the prototype. All instances will use that array. All instances will push to that array.
To fix it it is enough to do:
function B() {
A.call(this); // call superclass
this.addNumber(1);
this.addNumber(2);
}
By calling the superclass in B's constructor, you have created a numbers variable for each instance of B, along with 2 functions which enclose over that variable. Each instance will use its specific addNumbers function which uses its specific closured array.
Since you already did that, your inheritance scheme can be simplified as well:
B.prototype = Object.create(A.prototype);
Instead of creating a new object of type A and setting that to the prototype of B, you set the prototype of B to inherit directly from the prototype of A. You still have methods defined in A's constructor because you called the superclass. The advantage is that now you no longer create instances of A for each subclass and (perhaps more important) you can now pass arguments to the constructor:
function A(name) {
this.name = name;
}
function B(name) {
A.call(this, 'B' + name);
}
B.prototype = Object.create(A.prototype);
You can't have this scenario in your inheritance model.
You've got one "A" instance, and it's the prototype for the "B" constructor. Thus, each "B" instance shares that same closure variable in the "A" instance.

javascript inheritance using the prototype property

I'm trying to do inheritance in javascript. First of all, looking on the web I found this
function A() {}
function B(){}
B.prototype = new A() ;
B.prototype.constructor = B ;
This works, however when I use the prototype property of B it doesn't work anymore ( http://jsfiddle.net/jeanluca/eQBUx/ )
function A() {}
A.prototype.bar = function(){ return 'A'; }
function B() {}
B.prototype.bar = function(){ return 'B'; }
I realize you could do
function B(){ this.bar = function(){ ... } } ;
But I think this is definitely slower than defining it using the prototype. So how could I do inheritance in the second situation ?
Thnx
Here's your code:
function A() {}
A.prototype.bar = function(){ return 'A';}
function B() {}
B.prototype.bar = function(){ return 'B'; }
B.prototype = new A() ; // replaces B's "bar" with A's "bar
var b = new B ;
console.log(b.bar());
As you can see the problem is in your 6th line. You're first setting B.prototype.bar to a function in line 5 and then you immediately set B.prototype to new A in line 6 (effectively undoing what you did in line 5). The solution is to put line 6 before line 5:
function A() {}
A.prototype.bar = function(){ return 'A';}
function B() {}
B.prototype = new A() ; // now it will work
B.prototype.bar = function(){ return 'B'; }
var b = new B ;
console.log(b.bar());
See the demo for yourself: http://jsfiddle.net/eQBUx/1/
In addition I agree with Bergi: Stop using the new keyword.
Update: After reading your comment and understanding your problem in greater detail I would recommend you use my augment library for inheritance:
var A = Object.augment(function () {
this.constructor = function () {};
this.bar = function () {
return "A";
};
});
var B = A.augment(function (base) {
this.constructor = function () {};
this.bar = function () {
return "B" + base.bar.call(this);
};
});
var b = new B;
console.log(b.bar());
See the demo: http://jsfiddle.net/eQBUx/2/
Using this to assign properties breaks the prototype chain. It's very inefficient and you can't use it to get inheritance. So .. don't?
You're creating a property on a the prototype object which you completely replace afterwards. Do it the other way round, create the bar method on the new object. And don't use new!
function B() {}
// first create the prototype object
B.prototype = Object.create(A.prototype);
// then assign properties on it
B.prototype.bar = function(){ return 'B'; }

Variable is "undefined" when used in a different method?

I have this code for the setup of an object:
myObj.prototype.__init = function(a, b, c){
this.a = a;
this.b = b;
this.c = c;
}
And then in another function I want to use the a I setup in the __init method:
myObj.prototype.myFunc = function(){
var data = parse(a);
//...
}
The problem is that a is undefined. I also tried this.a and it results undefined too. The funny thing is that a console.log(myO) after doing a var myO = new myObj(); and myO.__init(myA, myB, myC); prints the object with the field a initialized. How do I access then a inside that function of my object?
Thanks
EDIT: This is the call to myFunc:
someVar = new tccHandler.myObj();
someVar.__init(myA, myB, myC);
someVar.myFunc();
I suspect it should be parse(this.a).
Remember that properties of this are not in the lookup-chain for identifiers [read: variables] by default; only lexical variables and properties of "the global object" (i.e. window) are.
a is a variable in the function __init (as a function parameter), where the object it names is assigned to the property this.a, but a is not a variable of the function myFunc. Each function introduces it's own lexical scope.
Happy coding!
In normal javascript, you would do:
myObj = function(a,b,c) {
this.a = a;
this.b = b;
this.c = c;
}
Demo:
> var x = new myObj(1,2,3);
> x.a;
1

How to add functions to prototype of inner function in the global scope in JavaScript?

function A() {
this.B = function() {
var bla;
};
}
A.B.prototype.foo = function() {console.log("Do whatever");};
I get this:
TypeError: Cannot read property 'prototype' of undefined
How to add a function to the prototype of B in this case?
There are a couple of mistakes in our code... here is how:
function A() {
this.B = function() {
var blah;
};
}
a = new A();
a.B.prototype.foo = function() {console.log("Do whatever")};
Your first issue was doing:
this.B() = function...
That's not valid code, since you were calling method B and assing it a function, you had to reference the attribute.
Your other mistake, was not instantiating an "A" object, the function by itself can't be used as an object, it can only be called. That's why when you had:
A.B.prototype
You recieved that error message.
I hope that clears things up a bit for you, let me know if you have more doubts.
B is a property of A, and can only be accessed from instances of A.
var aObj = new A;
aObj.B();
You cannot access A.B without using an instance of A.
You could access aObj.B.prototype, and add methods to that.
aObj.B.prototype.foo = function(){
return 'test';
};
var bar = new aObj.B;
console.log(bar.foo()); // 'test'
var bObj = new A;
var foobar = new bObj.B;
console.log(foobar.foo()); // `foo` is undefined
You need to make the inner function accessible by adding it to the outer prototype, then you can add functions to the inner object by using Outer.prototype.Inner.prototype without the immediate need for an instance of the outer object.
function A() {this.a="a";}
A.prototype.B = function() {this.b="b";}
A.prototype.B.prototype.foo = function() {console.log("b is:"+this.b);}
var a=new A();
var b=new a.B();
b.foo();

Categories