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/
Related
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.
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();
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
Please help explain the following result (tested on Firefox 3.6). How come this.constructor points to A inside prototype, if "this" is clearly of type B? I was under illusion that dictionary is traversed from topmost level down prototype chain, but it doesn't seem to be the case here:
A=function() {}
A.prototype.copy=function() {
return new this.constructor();
}
B=function() {}
B.prototype=new A();
var b=new B();
var bcopy=b.copy();
var cond1=bcopy.constructor==B // false
var cond2=bcopy.constructor==A // true
var b = new B;
b.constructor == A; // true
Thus, your copy() function is creating a new A. If, however, you add this line:
B.prototype.constructor = B;
...you will get the results you were hoping for.
I'm trying to understand inheritance in Javascript, but this code (tested in Firebug) doesn't work the way I'm expecting. What am I not understanding about it?
var A = function(v){
this.v = v || 'foo';
}
A.prototype.shout = function(){ alert(this.v); }
var B = function(){};
B.prototype = new A;
var test = new B('bar')
test.shout() // returns 'foo'
What I'm expecting is that when I assign test the property this.v is set to "bar". As far as I understand JS prototypical inheritance setting B's prototype to A's means everything in B is overwritten. I would expect then that it's constructor is overwritten, and that calling new B('bar') would execute A's constructor with the parameter "bar".
If my understanding is incorrect, could someone please correct me. It would also be good to find the solution to what I'm looking to do:
// constructors from above
B.prototype.yell = function(){ alert('hello world'); }
var test1 = new B('bar'), test2 = new B('spam'), test3 = new B('eggs');
...so that the JS objects I'm creating follow a similar inheritance pattern to standard OOP and therefore B would inherit A's constructor and methods.
Edit:
After reading the comments, I believe a better question would be to ask how would one overwrite B's constructor with A's?
Following is a constructor. It runs when you call new A.
var A = function(v){
this.v = v || 'foo';
}
In B constructor is function(){}; So you are not setting this.v
To achieve result you are trying you should follow this pattern:
var A = function(v){
this.v = v || 'foo';
}
A.prototype.shout = function(){ alert(this.v); }
var B = function(v){
B.prototype.constructor.call(this,v); // here you call A constructor
};
B.prototype = new A;
var test = new B('bar')
test.shout() // returns 'bar
When you set
var B = function(){};
you create a parameterless constructor B. Then when you do
B.prototype = new A;
you are calling the A constructor with no parameters (causing this.v = 'foo'), and then causing B's prototype to point to the v and shout from A. However, B as a constructor hasn't changed. This can be seen by adding some parameters to the definition of 'B', for example:
var B = function(x){this.v += x};
should produce 'foobar'.
Addendum:
The closest way I can think of to "copy" the constructor is actually to create both constructors with some third-party function and assign to both A & B. Example:
var objmaker = function(defaultval) {
return function(v) { this.v = v || defaultval; };
}
var A = objmaker('foo');
A.prototype.shout = function(){ alert(this.v); }
var B = objmaker('bar');
B.prototype = A.prototype; // B can now shout()
var testA1 = new A('A');
testA1.shout(); // returns 'A'
var testA2 = new A();
testA2.shout(); // returns default 'foo'
var testB1 = new B('B');
testB1.shout(); // returns 'B'
var testB2 = new B();
testB2.shout(); // returns default 'bar'
It's not really copying, as you can see by the different default values, but it is one way to ensure the two definitions stay in sync.
Instead of setting the prototype to a new instance of A, make B's prototype delegate up to A's prototype. Crockford calls this beget, it's implemented as dojo.delegate in Dojo. It's a simple function that looks like this:
function delegate(o){
F = function(){}
F.prototype = o;
return new F;
}
And you can use it to create this link between prototypes:
var B = function(){}
B.prototype = delegate(A.prototype);
By doing this, the A constructor never gets called, and the v value is never set. This limits inheritance to only the prototype, and not the prototype plus constructor.
Try
var test2 = new A('baz');
test2.shout(); //returns baz
I think when you make 'var B' a new function, rather than making it a' new A', you wipe out the 'constructor' you made 'A' as.
I'm not sure how the original is still getting invoked to set test's instance of v to 'foo'.
How about instead of trying to make javascript work like some other language, you could maybe learn something new from it, and use so it works like javascript?
have a look at this:
http://javascript.crockford.com/prototypal.html