Forum Moderators: open
What I want to know is if this example, using prototype and the object literal...
function Obj(prop1, prop2) {
this.p1 = prop1;
this.p2 = prop2;
}
Obj.prototype = {
greet : function() {
alert(this.p1);
},
getP2 : function() {
return this.p2;
}
}
is as efficient as this example, which just uses prototype? Do instances of the first example create copies of the private functions, or references to them?
function Obj(prop1, prop2) {
this.p1 = prop1;
this.p2 = prop2;
}
Obj.prototype.greet = function(){
alert(this.p1);
}
Obj.prototype.getP2 = function(){
return this.p2;
}
Thanks
DobbyM
[edited by: DobbyM at 2:47 pm (utc) on Feb. 13, 2008]
I get confused about prototypes and linking, though. I'll readily admit that. So I'll be interested to see if anyone has an answer for you that, yes, there's a difference there.
My sense, again maybe wrong, is that logically there is a prototype for every object/instance, which prototype is a collection/table of labels/objects. Some are 'private', some are exposed to inferior objects. But a new object/instance doesn't copy the public objects of its constructing or superior object, certainly not the private ones. It can substitute for them. It can contain labels/objects of the same name and type that would override any superior of the same. But when created, I don't think there's anything in the new prototype. Calls to methods are made along a one-way up chain, until a null prototype is encountered. It is a first found on the way up inheritance. Again, someone correct me if that's wrong. One adds to each prototype to 'extend' that object's methods. But some don't like this idea of doing it this way. And the YUI-type frameworks seem more broken out by namespace than by object creation/inheritance (which means functions and objects tend to refer to each other by the apex, Yahoo, in this case).
Obj.prototype = {
greet : function() {
alert(this.p1);
},
getP2 : function() {
return this.p2;
}
}
Obj.prototype.greet = function(){
alert(this.p1);
}
Obj.prototype.getP2 = function(){
return this.p2;
}
Those are essentially the same thing.
All functions have an empty prototype object in case they are used as a constructor. So your second example is the equivalent of this:
Obj.prototype = {};
Obj.prototype.greet = function(){
alert(this.p1);
}
Obj.prototype.getP2 = function(){
return this.p2;
}
The end result is the same. You have a prototype object containing 2 functions.
Do instances of the first example create copies of the private functions, or references to them?
All propertys are exposed to all other objects.
Functions not only are constructors, not only are objects, but have scope, and so a scope chain when using inheritance.
My confusion continues to be what the prototypes are supposed to include. Clearly one does not have to specifically use the "prototype" property. If you declare variables in the scope of a function, using it to construct other functions, those other functions can read that variable in the first, their constructor function. How would they execute a nested function in the constructor which was not assigned to a variable? or read its variables?
My confusion continues to be what the prototypes are supposed to include.
Essentially, it's inefficient to assign methods to an object in the constructor (each instance of that class gets identical copies of those methods). Since methods don't typically change, there's no need for each instance to have a copy... it would be more efficient if there was only 1 copy of the methods and they all shared it.
The prototype object is associated with the constructor. Each instance of the class inherits the methods and constants defined in the prototype, without making a copy for each instance. So it's more efficient.
If you declare variables in the scope of a function,
function foo() {
var x = 10;
}
using it to construct other functions,
function foo() {
var x = 10;
function bar() {
}
}
those other functions can read that variable in the first, their constructor function.
But I think this is where you were going with that:
function foo() {
var x = 10;
function bar() {
// I have access to x
alert("x = " + x);
}
bar();
}
In that example above, if I was to create a new foo() instance, the resulting object would have no public methods or variables, but each instance of foo would have a copy of a private var 'x', and a copy of the private method 'bar', which has access to foo's vars. Not efficient.
How would they execute a nested function in the constructor which was not assigned to a variable? or read its variables?
Now, here's a slightly different approach. In this example, I'm creating 'bar' as a public method:
function foo() {
var x = 10;
this.bar = function() {
alert("x: " + x);
}
}
var f = new foo();
f.bar();
So now the foo class has a public method 'bar' that can be called, which still has access to foo's private var 'x'. However, each instance of foo still has a copy of the bar method. Still not efficient.
In this example, I've moved 'bar' to the prototype object, so each instance of foo will share this one copy of 'bar'. But unfortunately, 'bar' doesn't have access to foo's private vars like this, so this will fail:
function foo() {
var x = 10;
}
foo.prototype.bar = function() {
alert("x: " + x);
}
var f = new foo();
f.bar();
If, however, we make x a public property, then the prototype can get at it:
function foo() {
this.x = 10;
}
foo.prototype.bar = function() {
alert("x: " + this.x);
}
var f = new foo();
var g = new foo();
g.x = 20;
f.bar();
g.bar();
In that example, there is only 1 'bar' method instance (in the prototype object) and it is shared by both instances of foo.
Dustin Diaz has written a good explanation
of private, public, and privileged methods [dustindiaz.com].
Dustin Diaz has written a good explanation
So I've been saying, and showing by example in other threads. But I have to disagree with him in this discussion of 'classes'. Javascript has a class, which is a property that tells the type of object. Otherwise, apart from primitives, javascript consists of objects, and prototype inheritance, not classes. Instead of specifically a class at the 'top', relying on instances for specifics, one instead simply modifies objects as one goes relying on first found upward inheritance, but through the prototype property and its collection. That's what confuses me.
unfortunately, 'bar' doesn't have access to foo's private vars like this, so this will fail:
Someone tried to correct me about that. But it's not so much private, as I understand it, but simply that these, along with the prototype property, are properties of the function object. Prototype's collection is just another property. These other properties, variables in this case, must be placed in the prototype collection property, or some reference made from within it (however it would be implemented).
each instance of foo would have a copy of a private [variables]
Wouldn't a new function object have a collection of its own, and its own prototype property. But wouldn't that prototype be empty, pointing only to the constructor's prototype. So these variables wouldn't be copied, since all the new function would be is just a collection with one member, its empty prototype object?
function fn() {
var x = 10;
this.b = function() {
alert("x: " + x);
}
}
var f = new fn();
f.b();
I found this also confusing. f now has only a prototype, an object Object, if you like, but nothing else. fn has a collection of x/value, and b/return value. Its prototype collection has a pointer to the b/return value, and an uplink to the constructor. The word, this, augments the prototype. As you say, an object using the keyword, this, is a public object, that is - part of the prototype collection. The constructor's own prototype collection isn't accessible to it. So there is no fn.b(). But, 'publicly', there will be an f.b().
So if one wishes to augment:
function func1() {
var x = 10;
this.y = function() { return typeof x; }
this.z = 5;
}var fn = new func1();
func1.prototype.T = fn.y() + "3";
alert(fn.T);
Here both y and z are in the prototype collection. But only fn can 'see' this prototype, and so can access y() directly. So to extend func1, and so make a new variable, T, available to fn, one has to use fn's access to the prototype when augumenting the func1 constructor, itself, in this way?
But I have to disagree with him in this discussion of 'classes'. Javascript has a class, which is a property that tells the type of object. Otherwise, apart from primitives, javascript consists of objects, and prototype inheritance, not classes.
var f = new foo();
f is an instance object of class foo.
Instead of specifically a class at the 'top', relying on instances for specifics, one instead simply modifies objects as one goes relying on first found upward inheritance, but through the prototype property and its collection. That's what confuses me.
Someone tried to correct me about that. But it's not so much private, as I understand it, but simply that these, along with the prototype property, are properties of the function object.
For example:
function foo() {
var x = 10;
}
// x is not defined outside of foo.
// Because x is not a "property" of foo
// we have no way to access it from outside
// of foo. It is only accessible within the
// scope of foo().
function bar() {
var y = 10;
function doThis() {
// doThis is defined within the scope
// of bar(), so therefore has access
// to y.
alert(y);
}
}
// Likewise, neither y or doThis are defined
// outside of bar(), and they are also not
// defined as properties of bar(), so therefore
// they can not be accessed outside of the scope
// of bar().
function acme() {
this.x = 10;
}
// acme now has a property 'x'. If we use acme()
// as a constructor, we create an instance of class
// acme, which will have property 'x'.
var a = new acme();
// We can now access the 'x' property of a
alert(a.x);
Prototype's collection is just another property.
function Dog() {
}
Dog.prototype = {
legs : 4
}
var fido = new Dog();
var spot = new Dog();
alert('fido has ' + fido.legs + ' legs');
// Above, we read the legs property from the
// prototype object
fido.legs = 3;
// And here, we are creating a new legs property
// within the fido instance of class Dog. The
// next time we try to read the legs property
// it will find a value within the fido instance
// and therefore not access the prototype's value.
// However, spot will still get it's value from
// the prototype.
each instance of foo would have a copy of a private [variables]Wouldn't a new function object have a collection of its own, and its own prototype property.
But wouldn't that prototype be empty, pointing only to the constructor's prototype.
So these variables wouldn't be copied, since all the new function would be is just a collection with one member, its empty prototype object?
function fn() {
var x = 10;
this.b = function() {
alert("x: " + x);
}
}
var f = new fn();
f.b();
I found this also confusing. f now has only a prototype, an object Object, if you like, but nothing else.
fn has a collection of x/value, and b/return value.
Its prototype collection has a pointer to the b/return value, and an uplink to the constructor.
The word, this, augments the prototype.
As you say, an object using the keyword, this, is a public object, that is - part of the prototype collection.
Here both y and z are in the prototype collection.
But only fn can 'see' this prototype, and so can access y() directly.
So to extend func1, and so make a new variable, T, available to fn, one has to use fn's access to the prototype when augumenting the func1 constructor, itself, in this way?
var f = new foo();f is an instance object of class foo.
Foo is an object of some particular type, called "class" in ECMA-262. Javascript doesn't present classes, but rather objects. Inheritance is had through objects. They inherit from the prototype property of their constructor object, called prototype-based inheritance.
And all constructor objects have a prototype. My confusion was that function instances were the end of the line, and could not again be used as constructors. A function's prototype is accessible to it by using the word, "prototype".
So
function func14(){
x = 15;
this.y = 20;
this.k = function(){ txt="y is " +y; alert(txt); return txt; }
func14.prototype.z2 = 50;
}alert(typeof func14) > "function"
alert(func14.x) > "undefined"
alert(func14.y) > "undefined"
alert(func14.z2) > "undefined"
alert(func14.prototype.z2) > "undefined"func14 collection (but not enumerable?):
name/value (key/context): x/15, y/20, k/<func literal>, prototype (empty), etcfunc14();
alert(func14.prototype.z2) > 50func14 prototype
name/value (key/context): z2/50Then:
var func14sub = new func14;
alert(typeof func14sub) > "object"
func14sub collection:
name/value (key/context): y/20, k/<func literal>, prototype ( z2/50 ), etc
Copying, not inheritance. I was confused about that. The "y" and "k" are simply copied to func14's object instance, func14sub.
Or are you saying that "x" is copied to func14sub's collection, as well? If so, how would it be enumerated as were these others? (see below)
That object instance, func14sub, also cannot itself be used to construct other objects, as could func14. Its class is "object", not "function". The reserved word, instanceOf, shows func14sub is an instance object, of func14 (func14sub instanceOf func14). However, func14sub did inherit, by the prototype, "z2". Your wrong-wrong-wrong, was right. And I was wrong. I don't know if prototypes are becoming clearer to me, and your wrong-wrong-wrongs would be fewer. I never came at this from the class-inheritance side, as many obviously did. I have no problem simply seeing javascript as based on object-inheritance, not class-inheritance, and would not even use the word, class, though I'll admit it is freely used in ECMA documents.
regular functions that are not used as constructors will not have a prototype object that can be used in any meaningful way.
All functions have prototype collections (an object) as a property. Any function object could be used to construct instance objects.
ECMA: A prototype property is automatically created for every function, to allow for the possibility that the function will be used as a constructor.
Functions are created with the function constructor - new Function or function xx(). The prototype property can then be assigned to any function at all. So once func1Sub is created, func1Sub.prototype = func2 now looks to func2 for its inheritance. But "new func1", etc, even though "new" is being used with a function, is not the function constructor but the construct property of the function, and does not create a new function, but a new instance object instead, of type - "object".
f is an instance of fn. It has a public method b(), and a private variable x. f's prototype object is an empty object (the default) since we didn't specify one for fn.
It seemed confusing to me. I agree with you.
prototype will have a constructor property
It's a property of the constructor.
ECMA: A constructor is a Function object that creates and initialises objects. Each constructor has an associated prototype object that is used to implement inheritance and shared properties. . . . The constructor’s associated prototype can be referenced by the program expression constructor.prototype, and properties added to an object’s prototype are shared, through inheritance, by all objects sharing the prototype.
So it's a bit circular. But you say that the prototype has a property, constructor, which obviously is not the same as constructor.prototype. So it might read - constructor.prototype.constructor?
I came across this as a way to enumerate what was in the collections:
if (!Array.forEach) { // mozilla already supports this
Array.forEach = function(array, block, context) {
for (var i = 0; i < array.length; i++) {
block.call(context, array[i], i, array);
}
};
}
Function.prototype.forEach = function(object, block, context) {
for (var key in object) {
if (typeof this.prototype[key] == "undefined") {
block.call(context, object[key], key, object);
}
}
};
String.forEach = function(string, block, context) {
Array.forEach(string.split(""), function(chr, index) {
block.call(context, chr, index, string);
});
};
var forEach = function(object, block, context) {
if (object) {
var resolve = Object; // default
if (object instanceof Function) {
// functions have a "length" property
resolve = Function;
} else if (object.forEach instanceof Function) {
// the object implements a custom forEach method so use that
object.forEach(block, context);
return;
} else if (typeof object == "string") {
// the object is a string
resolve = String;
} else if (typeof object.length == "number") {
// the object is array-like
resolve = Array;
}
resolve.forEach(object, block, context);
}
};
function alertx(context, objectkey, key, object){
alert(context +" : " +objectkey +" : " +key +" : " +object);
}forEach( <name> or <name.prototype> etc , alertx)
I believe it's just for FireFox/Mozilla that support this forEach.
And in "name/value (key/context): y/20, k/<func literal>, prototype ( z2/50 ), etc", I meant that prototype was func14's prototype, showing z2/50 when looking at func14Sub. Is the private var, "x", also part of func14Sub's collection/dictionary, what have you?
So:
Func1(){
Func1.prototype.func2 = function(){}
}Fn.prototype = new Func1();
Fn.prototype.constructor = Fn;
Fn.prototype.baseClass = Fn.prototype.constructor;function Fn(){}
var fn = new Fn();
fn.func2();