i've a nice problem here. I need to understand this
Foo = function(){
};
Foo.prototype = {
buttons: new Array(),
index:'',
add: function(value)
{
this.buttons.push(value);
},
clear:function(){
this.buttons=new Array();
},
count:function(){
return(this.buttons.length);
},
setIndex:function(index){
this.index;
},
getIndex:function(index){
return this.index;
}
};
var A= new Foo();
var B= new Foo();
A.add('toto');
B.add('tata');
A.setIndex(8);
B.setIndex(44);
alert(A.count()+"---"+A.getIndex());
That code gives me : "2---8" !!
So A.count() returns me A.count() + B.count(). Same with B.count() !!
Can anyone explain me this, already had this problem ? How to do ? i simply need the array "buttons" to be unique, proper to each object.
This is not how prototypical inheritance works, A and B have the same prototype, this means they have the same buttons array.
In JavaScript inheritance is prototypical, what you'd like is for each "Foo" object to have a separate buttons array but you're adding it to Foo's prototype so it's shared across all of its instances.
You can change this:
var Foo = function(){
};
To
Foo = function(){
this.buttons = []; //add an empty buttons array to every foo element.
};
That would make it work, another alternative would be to call the clear method first, it would instantiate a new buttons array.
Note that prototypical inheritance is mostly about sharing functionality and not properties. You'd like each of your Foo instances to have the same functionality but to each have their own buttons array.
Some resources to help you:
Here is a good tutorial about how the prototypical chain works on MDN
Here is Addy Osmani's (Google) chapter about the constructor pattern from his JavaScript patterns book
Some other tips on your code:
The syntax new Array() can be shortened to []. In setIndex you're not actually assigning the index to anything. index is probably better declared in the constructor function of Foo as well.
Note that when you're setting an object's property where such a property exists on the prototype chain it creates a new property on the object rather than modify that property on the prototype.
When you define the variable in the prototype it is shared across all instances of Foo. You have to define the behaviour in your object (function) Foo to have an instance of the array for each instance of Foo.
Related
What does the following code do:
WeatherWidget.prototype = new Widget;
where Widget is a constructor, and I want to extend the Widget 'class' with a new function WeatherWidget.
What is the new keyword doing there and what would happen if it is left out?
WeatherWidget.prototype = new Widget;
The new keyword calls Widget as a constructor and the return value is assigned to the prototype property. (If you would omit new, you would not call Widget unless you added an argument list, (). However, calling Widget that way might not be possible. It would certainly have the potential to spoil the global namespace if it is not strict mode code and the implementation is conforming to ECMAScript Ed. 5.x there, because then this in the constructor would refer to ECMAScript’s global object.)
But this approach actually comes from a really viral bad example in the old Netscape JavaScript 1.3 Guide (mirrored at Oracle, formerly Sun).
This way, your WeatherWidget instances will all inherit from the same Widget instance. The prototype chain will be:
[new WeatherWidget()] → [new Widget()] → [Widget.prototype] → …
This can be useful, but most of the time you would not want it to happen. You should not do that here unless you want all your WeatherWidget instances to share among them the property values they inherit from this Widget instance, and only through it, from Widget.prototype. Another problem is that you need to call the parent constructor this way, which may not allow to be called without arguments as you do, or would not initialize properly. It certainly has nothing to do with emulation of class-based inheritance as known, e.g., from Java.
The proper way to implement class-based inheritance in these prototype-based languages is (originally devised by Lasse Reichstein Nielsen in comp.lang.javascript in 2003, for cloning objects):
function Dummy () {}
Dummy.prototype = Widget.prototype;
WeatherWidget.prototype = new Dummy();
WeatherWidget.prototype.constructor = WeatherWidget;
The constructor prototype property should be fixed as well, so that your WeatherWidget instances w would have w.constructor === WeatherWidget as expected, and not w.constructor === Widget. However, be aware that it is enumerable afterwards.
This way, WeatherWidget instances will inherit properties through the prototype chain, but will not share property values among them, because they inherit from Widget.prototype through Dummy which has no own properties:
[new WeatherWidget()] → [new Dummy()] → [Widget.prototype] → …
In implementations of ECMAScript Ed. 5 and later, you can and should use
WeatherWidget.prototype = Object.create(Widget.prototype, {
constructor: {value: WeatherWidget}
});
instead. This has the additional advantage that the resulting constructor property is not writable, enumerable, or configurable.
The parent constructor will only be called if you call it explicitly, from WeatherWidget, for example with
function WeatherWidget (…)
{
Widget.apply(this, arguments);
}
See also Function.prototype.extend() in my JSX:object.js for how to generalize this. Using that code, it would become
WeatherWidget.extend(Widget);
My Function.prototype.extend() takes an optional second argument with which you can easily augment the prototype of WeatherWidget instances:
WeatherWidget.extend(Widget, {
foo: 42,
bar: "baz"
});
would be equivalent to
WeatherWidget.extend(Widget);
WeatherWidget.prototype.foo = 42;
WeatherWidget.prototype.bar = "baz";
You will still need to call the parent constructor explicitly in the child constructor, though; that part cannot reasonably be automated. But my Function.prototype.extend() adds a _super property to the Function instance which makes it easier:
function WeatherWidget (…)
{
WeatherWidget._super.apply(this, arguments);
}
Other people have implemented similar extensions.
According to some odd Javascript rules, new Widget actually invokes the constructor rather than returning a reference to the constructor. This question actually answers the question the difference between var a = new Widget() and var a = Widget().
In simple words, the new keyword tells Javascript to call the function Widget under a different set of rules than a regular function call. Going off the top of my head, the ones I remember are:
There is a brand new object created
Widget can use the this keyword to refer to that object.
If Widget does not return anything, this new object will be created.
This object will inherit a few additional properties that will indicate it was created by Widget that are used to track down property chains.
Without the new keyword, a call to widget would
If in strict mode, this will be set to undefined.
Otherwise, this will refer to the global object. (Called window by the browser.)
If the function does not return anything, then undefined will be returned.
Reference:
new keyword
WeatherWidget.prototype = new Widget;
does create a new instance of the Widget constructor and use it as WeatherWidget's prototype object. Using the new keyword creates the new object, sets up the inheritance chain of it to Widget.prototype, and applies the constructor function on it (where you can set up individual properties'n'methods, or create private-scoped variables).
Without the new keyword it would be an assignment of the Widget function to the prototype property - which does not make any sense. If you'd add the optional brackets (i.e. Widget()), it would invoke the function normally, but not as a constructor on a new instance, but with the global object as context. See also the reference for the this keyword.
Notice that you should not really use this code. As said, it creates a new instance by invoking the constructor function. But the purpose is only to create an empty object that inherits from the Widgets prototype object, not to instantiate something (which could do some harm, depending on the code). Instead, you should use Object.create (or its popular shim):
WeatherWidget.prototype = Object.create(Widget.prototype);
see also Javascript basic inheritance vs Crockford prototypical inheritance
In plain english you're extending one class with another. A prototype can only be an object so you set WeatherWidget's prototype to a new instance of Widget. If you removed the new keyword you would be setting the prototype to the literal constructor function which doesn't do anything.
var Appendages = function(){
this.legs = 2
};
var Features = function() {
this.ears = 4;
this.eyes = 1;
}
// Extend Features class with Appendages class.
Features.prototype = new Appendages;
var sara = new Features();
sara.legs;
// Returns 2.
Understanding that the prototype can be any object, something like this would also work:
var appendages = {
legs : 2
};
var Features = function() {
this.ears = 4;
this.eyes = 1;
}
// Extend Features class with Appendages class.
Features.prototype = appendages;
var sara = new Features();
sara.legs;
// Returns 2.
In JavaScript, if the key isn't found on the object, it checks the parents object you extended it from. Hence you can change items on the parent object on the fly like so:
var appendages = {
legs : 2
};
var Features = function() {
this.ears = 4;
this.eyes = 1;
}
// Extend Features class with Appendages class.
Features.prototype = appendages;
var sara = new Features();
sara.legs;
// Returns 2.
appendages.hair = true;
sara.hair;
// Returns true.
Note that this all happens during instantiation which means you can't just switch out the prototype after you've created the object:
var foo = {name : 'bob'};
var bar = {nachos : 'cheese'};
foo.prototype = bar;
foo.nachos;
// undefined
However, all modern browsers come with this newer __proto__ method, which allows you to do it:
var foo = {name : 'bob'};
var bar = {nachos : 'cheese'};
foo.__proto__ = bar;
foo.nachos
// "cheese"
Read up more on understanding JavaScript prototypes here.
This article from Pivotal Labs is also really good.
new is important for prototype inheritance; i.e.
Create a constructor with a method
var Obj = function(){};
Obj.prototype = {};
Obj.prototype.foo = function(){console.log('foo');};
Make a second constructor to extend the first with
var ExObj = function(){};
Now, if we prototype without new,
ExObj.prototype = Obj;
(new ExObj).foo(); // TypeError: Object #<Object> has no method 'foo'
Which means we haven't inherited from the prototype of Obj, however, if we prototype with new
ExObj.prototype = new Obj();
(new ExObj).foo(); // console logs 'foo'
Furthermore, adding new things to the prototype of ExObj doesn't make any changes to it's base, Obj.
JavaScript functions are "MULTIPLE(2) PERSONALITIES"!!!
They are regular-functions with input and output, which we call like function().
Also they are constructors of JS-objects, when we use the new keyword. >>>BUT<<< the new created objects are NOT INSTANCES of the constructors (like the objects of classes in class-based inheritance). The new objects are instances of the object of the prototype property of the constructor.
Then in WeatherWidget.prototype = you put the object you want to inherit its properties to the objects the constructor will create, which usually is new function() and not a function.
JavaScript created HUGE confusion in the programming community by naming the objects created by constructors, INSTANCES of them with the instanceof keyword.
> function f(){}
undefined
> new f() instanceof f
true
What does the following code do:
WeatherWidget.prototype = new Widget;
where Widget is a constructor, and I want to extend the Widget 'class' with a new function WeatherWidget.
What is the new keyword doing there and what would happen if it is left out?
WeatherWidget.prototype = new Widget;
The new keyword calls Widget as a constructor and the return value is assigned to the prototype property. (If you would omit new, you would not call Widget unless you added an argument list, (). However, calling Widget that way might not be possible. It would certainly have the potential to spoil the global namespace if it is not strict mode code and the implementation is conforming to ECMAScript Ed. 5.x there, because then this in the constructor would refer to ECMAScript’s global object.)
But this approach actually comes from a really viral bad example in the old Netscape JavaScript 1.3 Guide (mirrored at Oracle, formerly Sun).
This way, your WeatherWidget instances will all inherit from the same Widget instance. The prototype chain will be:
[new WeatherWidget()] → [new Widget()] → [Widget.prototype] → …
This can be useful, but most of the time you would not want it to happen. You should not do that here unless you want all your WeatherWidget instances to share among them the property values they inherit from this Widget instance, and only through it, from Widget.prototype. Another problem is that you need to call the parent constructor this way, which may not allow to be called without arguments as you do, or would not initialize properly. It certainly has nothing to do with emulation of class-based inheritance as known, e.g., from Java.
The proper way to implement class-based inheritance in these prototype-based languages is (originally devised by Lasse Reichstein Nielsen in comp.lang.javascript in 2003, for cloning objects):
function Dummy () {}
Dummy.prototype = Widget.prototype;
WeatherWidget.prototype = new Dummy();
WeatherWidget.prototype.constructor = WeatherWidget;
The constructor prototype property should be fixed as well, so that your WeatherWidget instances w would have w.constructor === WeatherWidget as expected, and not w.constructor === Widget. However, be aware that it is enumerable afterwards.
This way, WeatherWidget instances will inherit properties through the prototype chain, but will not share property values among them, because they inherit from Widget.prototype through Dummy which has no own properties:
[new WeatherWidget()] → [new Dummy()] → [Widget.prototype] → …
In implementations of ECMAScript Ed. 5 and later, you can and should use
WeatherWidget.prototype = Object.create(Widget.prototype, {
constructor: {value: WeatherWidget}
});
instead. This has the additional advantage that the resulting constructor property is not writable, enumerable, or configurable.
The parent constructor will only be called if you call it explicitly, from WeatherWidget, for example with
function WeatherWidget (…)
{
Widget.apply(this, arguments);
}
See also Function.prototype.extend() in my JSX:object.js for how to generalize this. Using that code, it would become
WeatherWidget.extend(Widget);
My Function.prototype.extend() takes an optional second argument with which you can easily augment the prototype of WeatherWidget instances:
WeatherWidget.extend(Widget, {
foo: 42,
bar: "baz"
});
would be equivalent to
WeatherWidget.extend(Widget);
WeatherWidget.prototype.foo = 42;
WeatherWidget.prototype.bar = "baz";
You will still need to call the parent constructor explicitly in the child constructor, though; that part cannot reasonably be automated. But my Function.prototype.extend() adds a _super property to the Function instance which makes it easier:
function WeatherWidget (…)
{
WeatherWidget._super.apply(this, arguments);
}
Other people have implemented similar extensions.
According to some odd Javascript rules, new Widget actually invokes the constructor rather than returning a reference to the constructor. This question actually answers the question the difference between var a = new Widget() and var a = Widget().
In simple words, the new keyword tells Javascript to call the function Widget under a different set of rules than a regular function call. Going off the top of my head, the ones I remember are:
There is a brand new object created
Widget can use the this keyword to refer to that object.
If Widget does not return anything, this new object will be created.
This object will inherit a few additional properties that will indicate it was created by Widget that are used to track down property chains.
Without the new keyword, a call to widget would
If in strict mode, this will be set to undefined.
Otherwise, this will refer to the global object. (Called window by the browser.)
If the function does not return anything, then undefined will be returned.
Reference:
new keyword
WeatherWidget.prototype = new Widget;
does create a new instance of the Widget constructor and use it as WeatherWidget's prototype object. Using the new keyword creates the new object, sets up the inheritance chain of it to Widget.prototype, and applies the constructor function on it (where you can set up individual properties'n'methods, or create private-scoped variables).
Without the new keyword it would be an assignment of the Widget function to the prototype property - which does not make any sense. If you'd add the optional brackets (i.e. Widget()), it would invoke the function normally, but not as a constructor on a new instance, but with the global object as context. See also the reference for the this keyword.
Notice that you should not really use this code. As said, it creates a new instance by invoking the constructor function. But the purpose is only to create an empty object that inherits from the Widgets prototype object, not to instantiate something (which could do some harm, depending on the code). Instead, you should use Object.create (or its popular shim):
WeatherWidget.prototype = Object.create(Widget.prototype);
see also Javascript basic inheritance vs Crockford prototypical inheritance
In plain english you're extending one class with another. A prototype can only be an object so you set WeatherWidget's prototype to a new instance of Widget. If you removed the new keyword you would be setting the prototype to the literal constructor function which doesn't do anything.
var Appendages = function(){
this.legs = 2
};
var Features = function() {
this.ears = 4;
this.eyes = 1;
}
// Extend Features class with Appendages class.
Features.prototype = new Appendages;
var sara = new Features();
sara.legs;
// Returns 2.
Understanding that the prototype can be any object, something like this would also work:
var appendages = {
legs : 2
};
var Features = function() {
this.ears = 4;
this.eyes = 1;
}
// Extend Features class with Appendages class.
Features.prototype = appendages;
var sara = new Features();
sara.legs;
// Returns 2.
In JavaScript, if the key isn't found on the object, it checks the parents object you extended it from. Hence you can change items on the parent object on the fly like so:
var appendages = {
legs : 2
};
var Features = function() {
this.ears = 4;
this.eyes = 1;
}
// Extend Features class with Appendages class.
Features.prototype = appendages;
var sara = new Features();
sara.legs;
// Returns 2.
appendages.hair = true;
sara.hair;
// Returns true.
Note that this all happens during instantiation which means you can't just switch out the prototype after you've created the object:
var foo = {name : 'bob'};
var bar = {nachos : 'cheese'};
foo.prototype = bar;
foo.nachos;
// undefined
However, all modern browsers come with this newer __proto__ method, which allows you to do it:
var foo = {name : 'bob'};
var bar = {nachos : 'cheese'};
foo.__proto__ = bar;
foo.nachos
// "cheese"
Read up more on understanding JavaScript prototypes here.
This article from Pivotal Labs is also really good.
new is important for prototype inheritance; i.e.
Create a constructor with a method
var Obj = function(){};
Obj.prototype = {};
Obj.prototype.foo = function(){console.log('foo');};
Make a second constructor to extend the first with
var ExObj = function(){};
Now, if we prototype without new,
ExObj.prototype = Obj;
(new ExObj).foo(); // TypeError: Object #<Object> has no method 'foo'
Which means we haven't inherited from the prototype of Obj, however, if we prototype with new
ExObj.prototype = new Obj();
(new ExObj).foo(); // console logs 'foo'
Furthermore, adding new things to the prototype of ExObj doesn't make any changes to it's base, Obj.
JavaScript functions are "MULTIPLE(2) PERSONALITIES"!!!
They are regular-functions with input and output, which we call like function().
Also they are constructors of JS-objects, when we use the new keyword. >>>BUT<<< the new created objects are NOT INSTANCES of the constructors (like the objects of classes in class-based inheritance). The new objects are instances of the object of the prototype property of the constructor.
Then in WeatherWidget.prototype = you put the object you want to inherit its properties to the objects the constructor will create, which usually is new function() and not a function.
JavaScript created HUGE confusion in the programming community by naming the objects created by constructors, INSTANCES of them with the instanceof keyword.
> function f(){}
undefined
> new f() instanceof f
true
I know JavaScript inheritence is much different than typical OO languages (Java, c++, etc.). Searching around, there also seems to be many different ways to create classes and class hierarchies. Because of this I'm confused about JavaScript inheritence.
Given the following code
if (!com) var com = {};
if (!com.foobar) com.foobar = {};
com.foobar.Foo = {
foo : "foo",
bar : "bar",
baz : function () {
return true;
}
};
Why is the following not allowed? Why is com.foobar.Foo not a constructor? Is it because Foo is not a function, but an object?
var baz = new com.foobar.Foo();
Since I cannot do the above, how would I create a new Foo?
If I want to extend Foo, I thought I would do this:
var bar = Object.create(com.foobar.Foo, {buz: {value: "neat"}});
.. but is bar a subtype of Foo or an instance of Foo? I'm leaning towards instance of Foo because the following prints 'undefine'
console.log(bar.prototype);
You're correct, you can't do var baz = new com.foobar.Foo(); because Foo is an object, not a function.
Object.create is used to set the prototype of a variable (i.e. bar.prototype = Object.create(/*etc etc*/)). For more information, see the MDN page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
Using Object.create properly results in bar being another object with the prototype of Foo. This means that anything Foo has can be used on bar, eg bar.bar === 'bar' (if that makes sense). Changes to Foo will be reflected in bar, but not the other way around. It's not quite a subtype. (JS is weird, but it's delightfully so.)
For more on this, check out MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
Javascript has no classes, only objects. When you create an object, it can also have a prototype, which is just another object that the created object will use to delegate calls to properties (or functions) it doesn't itself understand.
This works more or less like classic inheritance, since subclasses also delegate calls it doesn't understand to superclasses.
So, taking that lead, you'd like to make Foo a prototype for other objects you create; Foo would act somewhat like a superclass to the objects.
A handy function you already know about is the Object.create. You can use it to create a new object with a specific prototype, as you did:
var bar = Object.create(com.foobar.Foo, {buz: {value: "neat"}});
This means that bar will have a prototype of Foo and also will have an own property (i.e. not in the prototype) of buz.
Now, the prototype of bar, which points to Foo, can be found (at least in Chrome, since this is implementation specific) on the property __proto__. So this is true: bar.__proto__ === com.foobar.Foo.
Moving forward, if you want bar to also be a superclass prototype of another object, you'd do the same:
var subbar = Object.create(bar);
Makes sense? I'll later add more about Function, the property prototype and the new operator if you want....
You are not able to instantiate Foo because it is an object, not a function. You can accomplish that by creating a function and using prototype to set the instance methods:
// constructor method
com.foobar.Foo = function() {
this.foo = 'foo'
this.bar = 'bar'
}
com.foobar.Foo.prototype.baz = function() {
return true
}
Take a look at it running on jsfiddle: http://jsfiddle.net/DE7KZ/
I asked the question:
Why cant I declare a constructor instantiate an object and then access the prototype?
And you can see that I have marked the answer. I understand the response but Im a bit confused as to what he means by:
The prototype belongs to the class, not the instance:
Does this mean that javascript has a class in this example? I thought javascript was classless? It only has function constructors... At what point does a function constructor become a class? Is it when you add other members to it using the .prototype accessor?
Actually class is an OOP term, not really javascript. What is meant is that the prototype belongs to the constructor. So in
function MyConstructor(prop){
this.foo = prop || 'foo';
}
MyConstructor.prototype.bar = 'allways bar';
var mc1 = new MyConstructor('I am mc1'),
mc2 = new MyConstructor('I am mc2');
alert(mc1.bar) ; //=> allways bar
alert(mc2.bar) ; //=> allways bar
alert(mc1.foo) ; //=> I am mc1
alert(mc2.foo) ; //=> I am mc2
bar belongs to the constructors (MyConstructor) prototype. It will always be 'allways bar', for every instance. foo is an instance property (with a default value 'foo') and can be assigned with a different value for every instance.
Ya prototype of JavaScript is a concept quite similar to class but not exactly the same. Read the article below, it offers one of the best explanations available on internet on this issue.
http://www.crockford.com/javascript/inheritance.html
There are no classes in javascript.
Constructors are functions and have a prototype property that references an object. You can add functions to that object, or assign a new object to the prototype property to create an inheritance chain:
function MyConstructor () {
// initialise instance
}
MyConstructor.prototype.someMethod = function() {
// ...
};
MyConstructor.prototype.anotherMethod = function() {
// ...
};
or replace it with an instance of another constructor:
MyConstructor.prototype = new SomeOtherConstructor();
MyConstructor.prototype.constructor = MyConstructor;
and so on. Now when an instance of MyConstructor is created:
var anInstance = new MyConstructor();
The object returned by the constructor has MyConstructor.prototype as its internal [[prototype]] property and "inherits" its methods and properties (and those on its entire [[prototype]] chain).
So each instance of MyConstructor has its MyConstructor.prototype on its prototype chain. Note however that MyConstructor doesn't inherit from it's own prototype, it is only used by instances created by new MyConstructor.
I've been looking into doing inheritance in JavaScript the correct prototypal way, according to Douglas Crockford: http://javascript.crockford.com/prototypal.html
He writes: "So instead of creating classes, you make prototype objects, and then use the object function to make new instances"
I figured this was the way to do it:
var objA = {
func_a : function() {
alert('A');
}
};
var objB = Object.create(objA);
objB.func_a = function() {
alert('B');
}
objB.func_b = function() {
};
var objA_instance1 = Object.create(objA);
var objA_instance2 = Object.create(objA);
var objB_instance1 = Object.create(objB);
var objB_instance2 = Object.create(objB);
etc...
But wouldn't this mean that there are now four instances of func_a (since it's isn't part of objA.prototype, it's just "inside" it), or am I not understanding this correctly?
Also, is there any way I can reach the overridden function of a function (for example call objA.func_a inside objB.func_a)?
Thanks in advance.
There is only one instance of func_a, and it is defined on objA, that is because the Crockford's Object.create method uses that object (objA) simply as the prototype of your new objects:
console.log(objA_instance1.func_a == objA .func_a); // true
console.log(objA_instance2.func_a == objA .func_a); // true
func_a on your objA_instances are reached by the prototype chain, that objects don't really own that property:
console.log(objA_instance1.hasOwnProperty('func_a')); // false
console.log(objA_instance2.hasOwnProperty('func_a')); // false
You're confusing the prototype property of constructor functions with the internal [[Prototype]] property of objects, which is inaccessible (FF makes it available as __proto__); using Object.create() sets this internal property to its argument, so objA and objB will be the actual prototypes of your 'instance' objects, ie no function objects will be duplicated.
To call the overridden functions, access them via eg objA.func_a and use call() or apply() to use them on the specific instances, eg
objB.func_a = function() {
objA.func_a.call(this); // call overridden method with current `this`
};