Why does my javascript getter/setter require underscores? - javascript

Performing a [[Get]] or [[Put]] operation on a throws a RangeError that states Maximum call stack size exceeded pointing to the this.a in the getter and the = in the setter.
let someObject = {
get a() {
return this.a;
},
set a(val) {
this.a = val;
}
}
someObject.a; // Error
someObject.a = 5; // Error
If the properties inside the getter and setter are underscored they work however:
let someObject = {
get a() {
return this._a_;
},
set a(val) {
this._a_ = val;
}
}
I've tested this in both the node environment and the v10 engine in Chrome and the same thing happens.
Such confusion. Send help.

Because by doing return this.a you're accesing the a property, which triggers the getter function, which accesses the a property, which triggers the getter function, which accesses the a property, which triggers the getter function... Endless loop.
Same for setter.

You need to have a variable that has a different name then the getter/setter. The most common way is to prefix the variable with an _.
Otherwise if you don't do this you will have an endless loop of calls to the getter/setter.
class A {
constructor() {
this._a = '';
}
get a() {
// If we don't call it like this
// We will be calling the getter again
// Which in return will call itself again
return this._a
}
}

Once an object has been defined with a setter for some property, that setter is always used to set the property value — even inside the setter itself! If you attempt to set the property with simple assignment inside the setter, JavaScript will call the setter again, and you get infinite recursion.
Using a leading special character like "_" for a second "secret name" is a common convention. However, that property is still externally visible (though it can be made non-enumerable). Another approach available in newer JavaScript environments is to use a Symbol instance instead of a property name. Symbol instances guarantee that your internal property identifier cannot ever collide with another property name from some other source in the application.
So:
let someObject = function() {
var aKey = Symbol();
return {
get a() {
return this[aKey];
},
set a(value) {
this[aKey] = value;
}
};
}();
That code uses a closure to create a private variable for the actual property key for what externally looks like a property called "a". It won't be possible for any other code to accidentally "step on" the private actual property used by the setter/getter pair because that's what Symbol is for.

Related

cannot understand the Javascript setter and getter lookup in classes

I understand that JavaScript classes are syntactic sugar over prototypes and not works as pure classes in other OOP languages. But the problem here arises is on the getter and setter. When completely leaving getter and setter in the child class, it behaves normally but if I define any one of getter or setter broke these.
For example:
class A {
constructor() {
this.__value = "Default";
}
set value(value) {
console.log("setter called")
this.__value = value;
}
get value() {
console.log("getter called")
return this.__value;
}
}
class B extends A {
}
let b = new B();
b.value = 2;
console.log(b.value);
The above code works fine but if I define getter or setter in the child class the lookup won't go to parent class. I googled about it and found that, it is intentional and is ES standard. Then why when the child class has no methods the lookup reaches the parent class and able to access the getter and setter?
When you access an object property, either to set a value obj.prop = 'val' or to retrieve a value console.log(obj.prop), the engine will try to find that property in the object's prototype chain.
It starts at the instance. In this case, the instance doesn't have any properties, so it continues.
The next object is the instance's internal prototype, which is B.prototype. If B has the property name being looked at, it'll stop there. If there's a setter, and a value was assigned to the property, the setter will be invoked. If there's a getter, and the value being retrieved, the getter will be invoked.
That's it - once a property is found in the prototype chain, it'll stop searching.
If B.prototype didn't have the setter/getter, then the engine would proceed to the next object. The internal prototype of B.prototype is A.prototype. Then, A's setter or getter would be invoked.
It's possible to invoke the superclass's setters/getters from the child, but it looks a bit strange:
class A {
constructor() {
this.__value = "Default";
}
set value(value) {
console.log("setter called")
this.__value = value;
}
get value() {
console.log("getter called")
return this.__value;
}
}
class B extends A {
set value(value) {
console.log('sub setter calling super');
super.value = value;
}
get value() {
console.log('sub getter calling super');
return super.value;
}
}
let b = new B();
b.value = 2;
console.log(b.value);
After googling and lot of code execution I found an answer to my own question,If we define no accessors(getter or setter) in our child class the lookup will proceed towards the parent but if we set any accessor using the get or set descriptor in child class that will invoke the Object.defineProperty method and set the descriptor we mentioned.If we have both setter and getter there is no problem,but if we leave any one that leads to missing of those property in our current object.That's the reason why we get undefined as the undefined property gets undefined value.So literally we have found the value which is undefined thats the main reason we cannot proceed to the parent prototype as value(undefined) found in the current object and the lookup will stop.

hasOwnProperty returns true, when checked against parent object properties

My JavaScript code:
console.clear();
function BaseClass(nname) {
var name = nname;
this.bc_PublicProperty = "DefaultValue_BaseClass";
this.bc_getName = function GetName() {
return name;
};
this.bc_setName = function SetName(nname) {
name = nname;
};
}
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_PublicProperty = "DefaultValue_SubClass";
this.sc_getName = function GetName() {
return name;
};
this.sc_setName = function SetName(nname) {
name = nname;
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
console.log("hasOwnProperty check on subclass object 'sc' returns true for Method 'bc_getName'");
for (var pro in sc) {
console.log("Is " + pro + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, pro));
}
I have two objects (BaseClass and SubClass). One inherits from the other using the constructor pattern, as explained on MDN.
Now, when I iterate over all properties of the subclass object, they all return true for hasOwnProperty, even for the parent methods/properties, except constructor.
Does it mean, that it breaks when using the constructor pattern?
When I put public properties and methods in the constructor function, whether in BaseClass or SubClass, they will always be "marked" as own properties/methods. When I instead attach them to the respective prototype, the hasOwnProperty will output "false" for them.
Whether you put the public methods/properties to the prototype or to the constructor function itself, they will all be available for use in the subClass (--> SubClass2, --> SubClass3).
The only thing, that I can think of right now, why you should attach them to the prototype object, is because of efficiency reasons, as explained here, "Defining class methods"-section. In order not to add closures for every constructed instance.
Value Types should be declared on the prototype, but not for instance variables whose initial values are dependent on arguments to the constructor, or some other state at time of construction.
You can override both properties/functions irrespective of their place of declaration.
Also setting up getters and setters on the prototype, for instance to set or get a private variable, makes no sense, as the private variable has to be public, in order to be accessible by the getters and setters attached to the prototype.
Therefore it makes no sense to use getters and setters. You can access the public variable directly.
I have to adjust my question a bit now:
When do I need hasOwnProperty, if actually public props/functions should be declared on the prototype, which in turn will all output Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case, when it makes sense, to use hasOwnProperty.
console.clear();
var l = function(v) {
console.log(v);
};
function BaseClass(nname) {
this.bc_nameProp = nname;
this.bc_ownFunc = function() {
l("bc_ownFunc of BaseClass called");
};
this.bc_getName = function GetName() {
return this.bc_nameProp;
};
}
BaseClass.prototype.bc_getName = function GetName() {
return this.bc_nameProp;
};
BaseClass.prototype.bc_PublicProperty = "DefaultValue_BaseClass";
BaseClass.prototype.bc_setName = function SetName(nname) {
bc_nameProp = nname;
};
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_setName = function SetName(nname) {
bc_nameProp = nname;
};
this.bc_getName = function GetName() {
return "xyz";
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sc_getName = function GetName() {
return this.bc_nameProp;
};
SubClass.prototype.sc_PublicProperty = "DefaultValue_SubClass";
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
l("----- iterating over BaseClass properties ------");
l("");
for (var pro in bc) {
l("Is " + pro + " own property of BaseClass: --> " + Object.hasOwnProperty.call(bc, pro));
}
l("");
l("----- iterating over SubClass properties ------");
l("");
for (var p in sc) {
l("Is " + p + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, p));
}
l(bc.bc_getName());
l(sc.bc_getName());
l(sc.sc_getName());
Solution
When I asked this question, I was of the opinion, that when using classical inheritance in JavaScript, I can differentiate which properties/functions of my subclass directly belong to it, using hasOwnProperty. Which is not possible, as all the properties/functions of the parent prototype are copied to the prototype of the SubClass:
SubClass.prototype = Object.create(BaseClass.prototype);
All properties/functions attached to prototypes return "false", when using hasOwnProperty.
And if you have public properties/functions declared in the constructor functions of BaseClass and SubClass, all these properties return "true", when calling hasOwnProperty for these properties on the subclass.
These are copied to the SubClass using this statement:
BaseClass.call(this, nname);
So using hasOwnProperty while iterating over all properties of an obj of type SubClass, will output false for all properties/functions declared on prototype level and true for all properties/functions declared on constructor function level.
Now, I understand why using hasOwnProperty in this use case makes no sense.
Check that you're calling BaseClass.call(this) on SubClass's constructor, meaning that you're adding BaseClass properties and functions to the SubClass instance, because this is an instance of SubClass.
This is why hasOwnProperty returns true for all properties.
Wrong prototypes...
At the end of the day, you're not taking advantage of prototypes in JavaScript.
Functions that must be part of any instance of some prototype should be defined in the prototype itself.
var A = function() {};
A.prototype = {
doStuff: function() {}
};
Actually, the only benefit of defining functions during construction-time is that you ensure that an object will always define some functions/properties, but you're ensuring this once the object has been already created.
For me, there's a very small difference between the following ways of defining properties:
var A = function() {};
var instance = new A();
instance.text = "Hello, World!";
// or...
var A = function() {
this.text = "Hello, World!";
};
var instance = new A();
The first code sample defines a text property after the constructor has been called while the second one does it inside the constructor, but in both cases either this or instance are references to the same object (i.e. the instance of A).
With prototypes you ensure that all objects created from some constructor function will share the same members, and these members will be inherited and consumed using prototype chain.
About the OP's update...
The OP said a lot of things, but summarizing said:
[...] I have to adjust my question a bit now: When do I need
hasOwnProperty, if actually public props/functions should be declared
on the prototype, which in turn will all output
Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case,
when it makes sense, to use hasOwnProperty.
You're going in the wrong way... Why asking yourself when you need hasOwnProperty? Ask yourself when you need simple objects with less reusability or when you need actual reusability. hasOwnProperty has nothing to do with this issue.
When you use a literal object (i.e. ones declared as is with {} syntax)? When you need dictionaries, argument maps, value objects... Here you like hasOwnProperty because usually your code receiving arguments will look like this:
function X(uri, options) {
if(typeof options != "undefined") {
// For example, we set a default value if options has no
// mimeType property...
options.mimeType = options.hasOwnProperty("mimeType") ? options.mimeType : "application/json";
}
}
When do you use complex objects using prototypes? When you define behavior and you need to reuse it across your application or even multiple applications, and also you need to add more behavior on top of generic requirements (hello inheritance).
About why using hasOwnProperty...
The OP said:
But why would you use "hasOwnProperty" here, if you want to check the
existence of an property? Shouldn't it be: options.mimeType =
options.mimeType || "application/json";
There's a lot of code on the Internet doing the `options.mimeType =
options.mimeType || "application/json", right, because in JavaScript undefinedevaluates tofalse(ifoptionsdoesn't own amimeTypeproperty returnsundefined`).
In my humble opinion, I would use hasOwnProperty because it returns a boolean either if it exists or it exists and it has undefined as the value.
For example, options could be defined as { mimeType: undefined } and sometimes you want to know if the property exists even if it has undefined as value. The undefined as false treats the case of if it's undefined, either if it exists or not, do X, and hasOwnProperty is I want to be sure it has the property or not.
So why would I use options.hasOwnProperty over other approaches?. Easy: because, since language gives a tool to verify if a property exists in some object, why do I need a trick? object.hasOwnProperty returns true or false, and I'm sure the property exists or not, even if the property has undefined value.
With options.hasOwnProperty("mimeType") I can throw an Error if it exists and it has an undefined value. Why do I prefer this? Because I like the fail-fast concept: if you gave me the property with undefined value I tend to think that there's some bug in your code. Define it or not, my friend!
I'm going to assume by "constructor" pattern, you mean assigning this.fn = function (){}; and this.val = true; in the constructor function.
The this in the context of the BaseClass.call is changed to be the sub class, so all assignments within that are made on the sub class itself. Strictly speaking this isn't actually doing any sort of inheritance at all. Let me explain a bit in the code.
SubClass.prototype = Object.create(BaseClass.prototype);
In this line, you would be inheriting the prototype of the BaseClass on the sub class, which would ordinarily mean inheritance. However, the prototype for the BaseClass is the exact same prototype of the Function object, which the SubClass was already inheriting from. The this.___ assignments do not add to the prototype of an object, only to an instance of that object. To add to the prototype, you would need to do something along the lines of BaseClass.prototype.___ = 'foo'; However, you don't want to do that in the constructor, as that assignment is then happening every time you create a new object.
Also, in your code, calling SubClass.getName will throw an error. name is not defined in that context, only in the BaseClass context.

Creating properties in literal object

var o, d;
o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d is { configurable: true, enumerable: true, get: /*the getter function*/, set: undefined }
What does that get within the object do? Is that a method or property or something else?
How does it work or how it set property or method to object? Will i fall into trouble if i simply ignore the use of get and set?Are there more advantages in using get and set than simply defining property without there use.What are those advantages if any.Also what will the .getOwnPropertyDescriptor() method returns? If it returns object, can I simply do returnedobj.configurable to access the configurable property-value?
The get defines a property accessor function. When the value of the foo property on o is retrieved, that function is called even though it doesn't look like a function call in the code, e.g.:
var a = o.foo; // Note that `foo` doesn't have () after it, it's not a function call
In this case, it always returns 17, but it could do something else instead. For instance, consider a circle:
var circle = {
radius: 7,
get circumference() { return 2 * Math.PI * this.radius; },
get area() { return Math.PI * this.radius * this.radius; }
};
console.log(circle.circumference); // 43.982297150257104
console.log(circle.area); // 153.93804002589985
circle.radius = 4;
console.log(circle.circumference); // 25.132741228718345
console.log(circle.area); // 50.26548245743669
As you can see, when we access the two properties we defined with accessors, the functions assigned to them get called, even though the property access doesn't look like a function call.
You can also have functions that get called when the property is set. Unsurprisingly, you do that using set rather than get. :-)
You can read more about this in the object initializers part of the specification, and on MDN.
The Object.getOwnPropertyDescriptor call returns an object that describes the property you asked for (in this case, foo). You can read more about it in the spec and on MDN as well.
Quoting from MDN:
A property descriptor is a record (TJC: e.g., object) with some of the following attributes:
value
The value associated with the property (data descriptors only).
writable
true if and only if the value associated with the property may be changed (data descriptors only).
get
A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only).
set
A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only).
configurable
true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
enumerable
true if and only if this property shows up during enumeration of the properties on the corresponding object.
get is part of the ECMAScript 5 syntax for defining property getters and setters.
Using object literal syntax, it's defined like this:
var obj = {
__other_property__: null,
get foo() { return "bar"; },
set foo(v) { this.__other_property__ = v }
};
This lets you invoke the body of the getter function when doing a get on the property.
obj.foo = "oof";
console.log(obj.foo); // "bar"
console.log(obj.__other_property__); // "oof"
The above uses foo to set a different property __other_property__. This could be a local variable or something else, and the functions can obviously do far more complex operations than I'm showing here.

Define a property for a JavaScript object

Is such declaration of getter and setter for a property correct and most efficient?
var AxisRange = (function(){
function AxisRange(){
this._userMaxValue = 0.0;
Object.defineProperty(AxisRange.prototype, "UserMaxValue", {
get : function(){
return this._userMaxValue;
},
set : function(value){
if(value != this._userMaxValue){
this._userMaxValue = value;
this.validateUserMaxValue();
this.validateUserStep();
this.synchronizeActualRange();
}
}
});
}
AxisRange.prototype.validateUserMaxValue = function(){
alert("validateUserMaxValue");
};
return AxisRange;
})();
Also, I'm using JetBrains WebStorm to write my JS code, and it warns me that
AxisRange.prototype used in Object.defineProperty is not assignable to parameter type Object.
in line if(value != this._userMaxValue) is says "Possible invalid usage of this."
Before I go any further with code typing I need to make sure what I'm using is correct.
You're defining a prototype property inside the constructor. That means it will be re-defined every time you make a new AxisRange object. Move that out of the constructor function.
You also might want to get rid of that closure, because you're not using it to namespace any local variables and it will complicate attempts to optimize your JavaScript. (Google Closure Compiler will especially complain if you ever use it.)

Prototype or inline, what is the difference?

I am just learning Javascript and I was wondering, is using the prototype declaration, like this:
function TSomeObj()
{
this.name="my object";
}
TSomeObj.prototype.showname = function() {
alert(this.name);
}
Basically the same as doing it like this:
function TSomeObj()
{
this.name="my object";
this.showname = function() {
alert(this.name);
}
}
When I dump the object's properties I get the same result:
TSomeObj (inline version) =
{
'name': 'my object',
'test': function
}
TSomeObj (prototype declaration) =
{
'name': 'my object',
'test': function
}
What exactly is the benefit of using prototype declarations? Except less cluttering and more orderly sourcecode perhaps.
Update: I should perhaps have made it more clear that it was the final result i was curious about. The end result is ofcourse the same (i.e both register a new function in the object prototype) - but the way they do it is wildly different. Thank you for all replies and info!
Note: This answer is accurate but does not fully reflect the new way to create classes in JavaScript using the ES6 class Thing {} syntax. Everything here does in fact apply to ES6 classes, but might take some translation.
I initially answered the wrong question. Here is the answer to your actually-asked question. I'll leave my other notes in just in case they're helpful to someone.
Adding properties to an object in the constructor function through this.prop is different from doing so outside through Object.prototype.prop.
The most important difference is that when you add a property to the prototype of a function and instantiate a new object from it, that property is accessed in the new object by stepping up the inheritance chain rather than it being directly on the object.
var baseobj = {};
function ObjType1() {
this.prop = 2;
}
function ObjType2() {}
ObjType1.prototype = baseobj;
ObjType2.prototype = baseobj; // these now have the *same* prototype object.
ObjType1.prototype.prop = 1;
// identical to `baseobj.prop = 1` -- we're modifying the prototype
var a = new ObjType1(),
b = new ObjType2();
//a.hasOwnProperty('prop') : true
//b.hasOwnProperty('prop') : false -- it has no local property "prop"
//a: { prop = 2 }, b : { prop = 1 } -- b's "prop" comes from the inheritance chain
baseobj.prop = 3;
//b's value changed because we changed the prototype
//a: { prop = 2 }, b : { prop = 3 }
delete a.prop;
//a is now reflecting the prototype's "prop" instead of its own:
//a: { prop = 3 }, b : { prop = 3 }
A second difference is that adding properties to a prototype occurs once when that code executes, but adding properties to the object inside the constructor occurs each time a new object is created. This means using the prototype performs better and uses less memory, because no new storage is required until you set that same property on the leaf/proximate object.
Another difference is that internally-added functions have access to private variables and functions (those declared in the constructor with var, const, or let), and prototype-based or externally-added functions do not, simply because they have the wrong scope:
function Obj(initialx, initialy) {
var x = initialx,
y = initialy;
this.getX = function() {
return x;
}
var twoX = function() { // mostly identical to `function twoX() { ... }`
return x * 2;
}
this.getTwoX = function() {
return twoX();
}
}
Obj.prototype.getY = function() {
return y; // fails, even if you try `this.y`
}
Obj.prototype.twoY = function() {
return y * 2; // fails
}
Obj.prototype.getTwoY = function() {
return twoY(); // fails
}
var obj = new Obj();
// obj.y : fails, you can't access "y", it is internal
// obj.twoX() : fails, you can't access "twoX", it is internal
// obj.getTwoX() : works, it is "public" but has access to the twoX function
General notes about JavaScript objects, functions, and inheritance
All non-string and non-scalar variables in JavaScript are objects. (And some primitive types undergo boxing when a method is used on them such as true.toString() or 1.2.valueOf()). They all act somewhat like a hash/dictionary in that they have an unlimited(?) number of key/value pairs that can be assigned to them. The current list of primitives in JavaScript is: string, number, bigint, boolean, undefined, symbol, null.
Each object has an inheritance chain of "prototypes" that go all the way up to the base object. When you access a property of an object, if that property doesn't exist on the object itself, then the secret prototype of that object is checked, and if not present then that object's prototype, so on and so forth all the way up. Some browsers expose this prototype through the property __proto__. The more modern way to get the prototype of an object is Object.getPrototypeOf(obj). Regular objects don't have a prototype property because this property is for functions, to store the object that will be the prototype of any new objects created using that function as their constructor.
A JavaScript function is a special case of an object, that in addition to having the key/value pairs of an object also has parameters and a series of statements that are executed in order.
Every time a function object is invoked it is paired with another object that is accessed from within the function by the keyword this. Usually, the this object is the one that the function is a property of. For example, ''.replace() boxes the string literal to a String, then inside the replace function, this refers to that object. another example is when a function is attached to a DOM element (perhaps an onclick function on a button), then this refers to the DOM element. You can manually choose the paired this object dynamically using apply or call.
When a JavaScript function is invoked with the new keyword as in var obj = new Obj(), this causes a special thing to happen. If you don't specifically return anything, then instead of obj now containing the return value of the Obj function, it contains the this object that was paired with the function at invocation time, which will be a new empty object with the first parent in its inheritance chain set to Obj.prototype. The invoked Obj() function, while running, can modify the properties of the new object. Then that object is returned.
You don't have to worry much about the keyword constructor, just suffice it to say that obj.constructor points to the Obj function (so you can find the thing that created it), but you'll probably not need to use this for most things.
Back to your question. To understand the difference between modifying the properties of an object from within the constructor and modifying its prototype, try this:
var baseobj = {prop1: 'x'};
function TSomeObj() {
this.prop2 = 'y';
};
TSomeObj.prototype = baseobj;
var a = new TSomeObj();
//now dump the properties of `a`
a.prop1 = 'z';
baseobj.prop1 = 'w';
baseobj.prop2 = 'q';
//dump properties of `a` again
delete a.prop1;
//dump properties of `a` again
You'll see that setting a.prop1 is actually creating a new property of the proximate object, but it doesn't overwrite the base object's prop1. When you remove prop1 from a then you get the inherited prop1 that we changed. Also, even though we added prop2 after a was created, a still has that property. This is because javascript uses prototype inheritance rather than classic inheritance. When you modify the prototype of TSomeObj you also modify all its previously-instantiated objects because they are actively inheriting from it.
When you instantiate a class in any programing language, the new object takes on the properties of its "constructor" class (which we usually think of as synonymous with the object). And in most programming languages, you can't change the properties or methods of the class or the instantiated object, except by stopping your program and changing the class declaration.
Javascript, though, lets you modify the properties of objects and "classes" at run-time, and all instantiated objects of that type class are also modified unless they have their own properties that override the modification. Objects can beget objects which can beget objects, so this works in a chain all the way up to the base Object class. I put "classes" in quotes because there really isn't such a thing as a class in JavaScript (even in ES6, it's mostly syntactic sugar), except that the new keyword lets you make new objects with the inheritance chain hooked up for you, so we call them classes even though they're just the result of constructor functions being called with the new keyword.
Some other notes: functions have a Function constructor, objects have an Object constructor. The prototype of the Function constructor is (surprise, surprise) Object.
Inheriting from an object without the constructor function running
In some cases, it's useful to be able to create a new "instance of an object" without the constructor function running. You can inherit from a class without running the class's constructor function like so (almost like manually doing child.__proto__ = parent):
function inheritFrom(Class) {
function F() {};
F.prototype = Class.prototype;
return new F();
}
A better way to do this now is Object.setPrototypeOf().
The accepted answer missed the most important distinctions between prototypes and methods bound to a specific object, so I'm going to clarify
Prototype'd functions are only ever declared once. Functions attached using
this.method = function(){}
are redeclared again and again whenever you create an instance of the class. Prototypes are, thus, generally the preferred way to attach functions to a class since they use less memory since every instance of that class uses the same functions. As Erik pointed out, however, functions attached using prototypes vs attached to a specific object have a different scope, so prototypes don't have access to "private" variables defined in a function constructor.
As for what a prototype actually is, since it's an odd concept coming from traditional OO languages:
Whenever you create a new instance of a function:
var obj = new Foo();
the following logic is run (not literally this code, but something similar):
var inheritsFrom = Foo,
objectInstance = {};
objectInstance.__proto__ = inheritsFrom.prototype;
inheritsFrom.apply( objectInstance, arguments );
return objectInstance;
so:
A new object is created, {}, to represent the new instance of the function
The prototype of the function is copied to __proto__ of the new object. Note that this is a copy-by-reference, so Foo.prototype and objectInstance.__proto__ now refer to the same object and changes made in one can be seen in the other immediately.
The function is called with this new object being set as this in the function
and whenever you try to access a function or property, e.g.: obj.bar(), the following logic gets run:
if( obj.hasOwnProperty('bar') ) {
// use obj.bar
} else if( obj.__proto__ ){
var proto = obj.__proto__;
while(proto){
if( proto.hasOwnProperty('bar') ){
// use proto.bar;
}
proto = proto.__proto__;
}
}
in other words, the following are checked:
obj.bar
obj.__proto__.bar
obj.__proto__.__proto__.bar
obj.__proto__.__proto__.__proto__.bar
... etc
until __proto__ eventually equals null because you've reached the end of the prototype chain.
Many browsers actually expose __proto__ now, so you can inspect it in Firebug or the Console in Chrome/Safari. IE doesn't expose it (and may very well have a different name for the same thing internally).

Categories