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.
Related
function b(){
this.var = 20;
ele = 10;
}
let a = new b()
Because i can see neither ele nor this.var is stored in the b.prototype constructor.
If you want to store a property on a prototype just add it via "prototype"
function b(){
this.var = 20;
}
b.prototype.ele = 10;
let a = new b();
You will be able to access it directly through the created instance "a"
a.ele //will return 10
Remember that prototype is a single object, so every instance created with the same constructor will link to a single prototype.
Every instance has it's own scope, but shares a single prototype. It is important from performance perspective.
You have to be a little careful about declaring variables in Javascript. Your current code creates a global variable ele (it's added as a property of the window object) because you haven't declared it with var, let etc.
For example:
function b() {
this.var = 20;
ele = 10;
}
let a = new b()
console.log("ele is visible outside: ", ele)
console.log("ele is same as window.ele: ", ele === window.ele)
The answer to your main questions is no, instance variables are not stored on the functions prototype. Calling new b() will create a new object that has properties you assigned using this. That object is linked to the function's prototype through prototypical inheritance:
function b() {
this.var = 20;
}
let a = new b()
console.log("b.prototype.var?", b.prototype.var)
console.log("a.var?", a.var)
Because of prototype chaining if you assign something to b's prototype it will be available to instances of b (so long as they don't already have the same property of their own).
function b() {
this.var = 20;
}
b.prototype.testArray = [1, 2, 3]
let a = new b()
let c = new b()
console.log(a.test, c.test)
console.log("They point to the same object?", a.test === c.test)
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/
I know you can have one javascript instantiated object inherit the prototype of another constructor with constructer.prototype.__proto__ = otherConstructer.prototype, but can you use the call method like this to do the same thing?:
function constructor () {
otherConstructor.call(this);
}
No, the prototype can't be replaced except by referencing the object itself and directly replacing it with the __proto__ property, which doesn't exist in all implementations. Look at this sample code:
function B() {
this.someValue = "BBB";
}
B.prototype.testfunc = function() {
console.log("Called from B: someValue =" + this.someValue);
}
function A() {
this.someValue = "AAA";
return B.call(this);
}
A.prototype.testfunc = function() {
console.log("Called from A: someValue =" + this.someValue);
}
var test = new A();
test.testfunc();
// Will output "Called from A: someValue =BBB"
As you can see, the B constructor is correctly called and the object setup is from B and not A, but nevertheless the object's prototype is still from A. You can, of course, replace individual functions:
test.testfunc = B.prototype.testfunc;
test.testfunc();
// Will output "Called from A: someValue =BBB"
If you want a great explanation of why this is so, check out the accepted answer to this question.
Edit: There is no association with B.prototype when an A object is created. If you changed the code so that A.prototype.testfunc is not defined, then even though the A constructor calls B, nevertheless calling test.testfunc() will result in an undefined exception.
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
Using pure JavaScript to do inheritance, this is what I usually do:
function A() {}
A.prototype.run = function () {};
function B() {}
B.prototype = new A;
B.prototype.constructor = B;
Since there is no arguments to pass into the constructor, new A has nothing to complain about. Now, I haven't figured out a good way to do inheritance if the constructor has arguments to pass. For example,
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {}
B.prototype = new A;
B.prototype.constructor = B;
I could pass some arbitrary values like:
B.prototype = new A(null, null);
In some cases, I may need to validate x and y in the constructor of A. In some extreme cases, I need throw errors when checking x or y. Then, there is no way for B to inherit from A using new A.
Any suggestions?
Thanks!
Well, if you want to make B.prototype an object that inherits from A.prototype, without executing the A constructor, to avoid all possible side-effects, you could use a dummy constructor to do it, for example:
function tmp() {}
tmp.prototype = A.prototype;
B.prototype = new tmp();
B.prototype.constructor = B;
You could create a function to encapsulate the logic of the creation of this new object, e.g.:
function inherit(o) {
function F() {}; // Dummy constructor
F.prototype = o;
return new F();
}
//...
B.prototype = inherit(A.prototype);
B.prototype.constructor = B;
If you target modern browsers, you could use the ECMAScript 5 Object.create method for the same purpose, e.g.:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
//..
Although this is an old topic, I thought I'd respond anyway.
Two ways to do it:
Although the Pseudo Classical way is the most popular, it has its down sides since it needs to call the parent constructor once in the child constructor and once while inheriting the prototype. Besides, the child's prototype will contain all the properties of the parent constructor which will anyway get overwritten when the child constructor is called. My personal choice is Prototypal Inheritance.
1. Pseudo Classical Inheritance:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = new A();
B.prototype.constructor = B;
2. Prototypal Inheritance:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
The problem is that you can't easily create a prototype object for B since invoking the constructor of A can't be done. This is due to the parameters for the constructor being unknown before new B is executed. You need a dummy constructor function to construct a prototype for B that links to A's prototype.
B.prototype = (function(parent){
function protoCreator(){};
protoCreator.prototype = parent.prototype;
// Construct an object linking to A.prototype without calling constructor of A
return new protoCreator();
})(A);
Once you've got the prototype object for B set up, you need to ensure to call the constructor of A in the constructor of B.
function B(x, y) {
// Replace arguments by an array with A's arguments in case A and B differ in parameters
A.apply(this, arguments);
}
You should now be able to instantiate B by calling new B(x, y).
For a complete same including parameter validation in A see a jsFiddle.
In your original code you are setting B.prototype.constructor = B. I'm not getting why you are doing this. The constructor property does not influence the inheritance hierarchy for which the prototype property is responsible. If you want to have the named constructor contained in the constructor property you'd need to extend the code from above a little:
// Create child's prototype – Without calling A
B.prototype = (function(parent, child){
function protoCreator(){
this.constructor = child.prototype.constructor
};
protoCreator.prototype = parent.prototype;
return new protoCreator();
})(A, B);
Using the first definition of B.prototype you'd get the following results:
var b = new B(4, 6);
b.constructor // A
console.info(b instanceof A); // true
console.info(b instanceof B); // true
With the extended version, you'll get:
var b = new B(4, 6);
b.constructor // B
console.info(b instanceof A); // true
console.info(b instanceof B); // true
The cause for the different output is that instanceof follows up the whole prototype chain of b and tries to find a matching prototype object for A.prototype or B.prototype (in the other call). The b.constructor prototype does refers to the function that was used to define the instances prototype. In case you wonder why it does not point to protoCreator this is because its prototype was overwritten with A.prototype during the creation of B.prototype. The extended definition as show in the updated example fixes this constructor property to point to a more appropriate (because probably more expected) function.
For daily use, I'd recommend to discard the idea of using the constructor property of instances entirely. Instead do use instanceof since its results are more predictable/expected.
Consider this:
function B( x, y ) {
var b = Object.create( new A( x, y ) );
// augment b with properties or methods if you want to
return b;
}
And then
var b = new B( 12, 13 );
Now b inherits from an instance of A, which in turn inherits from A.prototype.
Live demo: http://jsfiddle.net/BfFkU/
Object.create isn't implemented in IE8, but one can easily manually implement it:
if ( !Object.create ) {
Object.create = function ( o ) {
function F() {}
F.prototype = o;
return new F();
};
}
This can be placed inside a ie8.js file which is loaded only for IE8 and below via conditional comments.