Use cases and syntax for non-object constructor functions? - javascript

Currently reading js.info and came upon this:
"Let’s note once again – technically, any function (except arrow functions, as they don’t have this) can be used as a constructor. It can be run with new, and it will execute the algorithm above. The “capital letter first” is a common agreement, to make it clear that a function is to be run with new."
This is the function they included but it doesn't seem to portray what they described. I also couldn't get it to run at all (several errors).
// create a function and immediately call it with new
let user = new function() {
this.name = "John";
this.isAdmin = false;
// ...other code for user creation
// maybe complex logic and statements
// local variables etc
};
I'm curious what this would look like in practice and what use cases exist for a constructor function that does not return/pertain to an object?

As for use cases: constructor functions are de facto object factories. It might be that you want to hide complicated/non-standard construction details from client code while maintaining a familiar construction API using new. The ability to return any object you like from a constructor function invoked with new enables this.
More info
Let's rearrange your code to make it a little easier to follow (this is only marginally different in that the constructor function now will have an inferred name 'F'):
let F = function() {
this.name = "John";
this.isAdmin = false;
// ...other code for user creation
// maybe complex logic and statements
// local variables etc
};
let user = new F; // or `new F();` if you prefer, parens are optional
console.log(Object.getPrototypeOf(user) === F.prototype) // true
When F is invoked with new:
A new object o is immediately created, with its [[Prototype]] set to refer to the .prototype property of function F.
The this value inside F is set to be o for the duration of the invocation of F as a constructor function.
The .constructor property of o is set to point to F
The return value of F is automatically set to be o if no value is explicitly returned.
Most constructor functions do not explicitly return an object. This is because invocation with new implicitly creates a new object, o, configured according to the rules of prototypical inheritance; o is set to be the this value used for the duration of the execution of the constructor function, and o is automatically and implicitly returned if no value is explicitly returned.
That said, programmers can instead explicitly return any object they like from a constructor function, and this overrides and prevents the implicit return.
Any function that implements the [[Construct]] internal method can be used as a constructor function with new (and super).
Ordinary function declarations (function foo() { ... }) and class constructors (class foo { constructor() {} }) can be used as constructor functions. Fat arrow functions, object literal methods, async functions and class methods cannot be used as constructor functions because they don't have the [[Construct]] internal method.

Related

javascript: what do the new keywords do internally

I know there are maybe a million similar questions out there already, e.g.,
here: what is the new keyword
here: typeerror: x is not a constructor
here: __proto__ vs prototype
here: MDN doc: new operator
but please hear me out.
The code:
let f = function(){console.log(".f.")};
fn = new f();
// Now:
typeof fn === "object" //true
//! fn() //TypeError: fn is not a function
//! new fn() //TypeError: fn is not a constructor
The general question would be: is it possible to create a "newable" object fn, by manipulating the functionf.
The question breaks down to the internal of the "new" keywords.
My doubt is, according to the MDN document, when a new keyword is used, the constructor of an class or function is called. However, even though fn.__proto__.constructor === f is true like all other javascript functions, fn is of type'object' (can we somehow alter it to 'function'?), and new fn() throws TypeError.
We can even add more to the mix by doing:
fn.constructor = f.constructor
fn.__proto__ = f.__proto__
fn.prototype = f.prototype
// f.constructor === Function //true
//! fn.call(this) //fn.call is not a function
still, fn() won't work, neither does new fn or new fn().
Why?
The new-able objects in JavaScript are:
Functions created using the function keyword (excluding generator functions)
Classes (which can be treated as functions)
Bound function exotic objects ("bound functions")
Some host objects
Proxies if they are applied to one of the above
I know this because the only object types the new operator works with are "constructors" (specification term). A constructor is an object with a [[Construct]] internal method, and you can search the ECMAScript specification to find out which kinds of object have a [[Construct]] internal method.
To make the result of a constructor function new-able, therefore, you must return one of the object kinds listed above.
Note that the specification specifically says that all constructors are definitionally functions because they must support the [[Call]] internal method (note also the caveat below about host objects).
If you want to get very advanced, then you may be interested to learn that host objects do not appear to share the ordinary limitations for constructors (presumably for legacy Web compatibility reasons), but these are exceptional.
Explanation of the .constructor property
When a new-able function f is declared, two objects are created: the function-object f itself, and a default object on the .prototype own-property of f. The .constructor property of this default .prototype object is automatically set by the runtime to be f. I believe classes work in a very similar fashion. Note that the fact that the name of this property was chosen to be "prototype" makes discussing prototypes quite confusing in JavaScript (as it is distinct from the [[prototype]] of the function).
This constructor own-property on the object positioned on the .prototype property, is never read by any built-in function or operation (that I know of). I view it as vestigial from the earliest days of JavaScript - it's original intent was as a way to maintain a link between the "class" that constructed an object as a developer affordance. Host environments (eg browsers) sometimes use it to infer the "type" of an object for the purposes of communicating with the user (eg. console output), the property is writeable and therefore unreliable.
Steps performed by the new operator
At a high level, when new is invoked against a constructor, the following steps occur (spec contains full details):
A new object o is created
The [[Prototype]] ("the prototype") of o is set to the value of the .prototype property of the constructor (note this means the .constructor property is inherited by the new object)
The target (ie this) of the constructor body is set to o
The constructor is run with the this value defined above
If there is no explicit object-type return value, then o is returned by default
The Scope: we exam the new on Function only. because this is the part that confuse the most. Calling new on Class yield results similar to that from other major OOP languages.
The original question could be break down to the following two questions:
What is the detailed construction process, when a new keyword is called?
How does JavaScript decide if an Object is Callable? (Thanks for #BenAston mentioning that the new keywords may only works with a limited set of Objects (e.g., prefixed with Class or Function))
Answer to the first question:
Back to the MDN Document,
When the code new Foo(...) is executed, the following things happen:
A new object is created, inheriting from Foo.prototype.
The constructor function Foo is called with the specified arguments, and with this bound to the newly created object. new Foo is equivalent to new Foo(), i.e. if no argument list is specified, Foo is called without arguments.
The object (not null, false, 3.1415 or other primitive types) returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't explicitly return an object, the object created in step 1 is used instead.(Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)
The words might be ambiguous,
But the PoC code is as follows:
// Case1, function has no return value;
// A new object is created, f0n.__proto__ === f0.prototype
let f0 = function() {};
f0.prototype.f0p = "f0p";
let f0n = new f0();
console.log(f0n) // f0n is a new Object, inheriting from f0.prototype
console.log(f0n.__proto__.f0p); // "f0p"
// Case3, function has an explicit return value, the value is an object
// (not null, false, 3.1415 or other primitive types);
// the return value becomes the new object value.
let f3 = function() {
return {
"f3": "f3"
}
};
f3.prototype.f3p = "f3p";
let f3n = new f3();
console.log(f3n) // {f3: "f3"}
// f3n is an Object, the return value of its constructor function `f3`
console.log(f3n.__proto__.f3p); // undefined
// Case4 (or Case1 again), function has an **implicit** return value.
let f4 = function(a) {
return (a + a)
};
f4.prototype.f4p = "f4p";
let f4n = new f4();
console.log(f4n.__proto__.f4p); // "f4p"
2.Answer to the second question:
I still do not yet know how JavaScript decide if a object is callable. The answer should be hiding in the ECMAScripts spec. (Thanks #BenAston for pointing out)
It might be legit to assume that only Function is callable. And the following post provide a workaround:
How to make an object callable
extra: how to return an Callable?
Use the Case3, let f = Function(){return Function(){}}
Since the return value is an non-primitive explicit Object, it becomes the result of the new directive. The result is a function, which could then be called.

Can you initialize a function? - Javascript

I have this function here, I need to work with this other function called OrderRepository in another file.
main.js
function main() {
var orderRepo = new OrderRepository();
// Your code here
}
orderrepository.js
function OrderRepository() {
}
OrderRepository.prototype.getYesterdaysOrders = function
getYesterdaysOrders() {
var yesterdaysOrders = [{ array of objects }],
return yesterdaysOrders;
};
These were given as examples to use, 1 question rolled into 2 parts:
1) var orderRepo = new OrderRepository();
Can you initialize a function like this?
2) In the orderrepository.js:
function OrderRepository() {
}
is being called in main.js, but nothings inside of it, this was given as-is in the assignment, is this just a typo and really they meant to throw everything inside that function or am I missing something?
Shouldn't it look like this?
Expected
function OrderRepository() {
OrderRepository.prototype.getYesterdaysOrders = function
getYesterdaysOrders() {
var yesterdaysOrders = [{ array of objects }],
return yesterdaysOrders;
};
}
Diving deeper into JavaScript, the language is hard to understand. JavaScript is not really OOP (imho), at least it does not implement the common OOP concept. Some call it object-based language. There are no classes. Recent ECMA Script standards do implement the class keyword, however, it is syntax sugar. Used with the new keyword it builds the same objects as you can achieve by 'constructor' functions.
Everything in JavaScript is an object, even numbers and functions. Every function can act as constructor function. The new keyword call a constructor function with a newly creates empty object as the function's this context. The function can do what it wants. If it does not return anything, its this context is returned by the new expression.
Since there are no classes, there is no inheritance. Some inheritance-like behavior is achieved by the prototype concept. In most cases the constructor will return nothing and sometimes modify the this object by adding properties. Methods are properties holding a function object. The object in the new context of a constructor call will have a prototype object reference as the __proto__ property. This is copied by the new operator from the prototype property of the called constructor function. The default is an empty object.
// empty constructor function
function OrderRepository() {
}
// define a function property on the constructor's prototype object
OrderRepository.prototype.getYesterdaysOrders = function
getYesterdaysOrders() {
var yesterdaysOrders = [ /* array of objects */ ],
return yesterdaysOrders;
};
// create an empty object with a `__proto__` property holding a
// reference to the object { getYesterdaysOrders: function(){/*code*/} }
var obj = new OrderRepository();
Now, when the method invocation obj.getYesterdaysOrders() is tried, JavaScript will look if there is such a property defined in obj. If not, it looks if there is a reference in obj.__proto__ and the property name is searched the properties of obj.__proto__. If not, the same step is repeated until it was found or the __proto__ property in the chain is null. Since obj.__proto__.getYesterdaysOrders is defined, it is checked if it is a callable function object and finally invoked with a this context of obj since we called obj.getYesterdaysOrders(). Otherwise an error is thrown.
NOTE: Even if the major browsers do expose the __proto__ property, it is not part of the standards. Do not use it directly (except for debugging at development time) and even more important: do not manipulate it. If you really need to get or manipulate a prototype (__proto__) of an object instance after construction, use the methods of the builtin Object object.
Upon your last edit: Your expected code would define a new function object in prototype on each instantiation (and thus constructor invocation). This is not what you want, it's just needless overhead.
Regarding the first part, it looks like this assignment is dealing with how to create instances of objects in JavaScript as that is what the new operator does.
You can find more information regarding new on the MDN.
Regarding the second question, it is dealing with how to create objects that inherit methods. So, yes it is empty, until you get to the prototype expression.
The expected code would not give you the inheritance in this case. Notice how OrderRepository is repeated inside the function, which would be invalid. Javascript requires you to add inheritance to the special prototype property. Code that is added to the function declaration, would be scoped to the function only in that case.
You can find more information about prototype on the MDN.

Confused on Prototype inheritance Javascript

I found this picture here
In this case, foo is a constructor function and B and C are objects. I am very confused, first off when you create an object does it always come with the properties and proto? Is that the default? Also in terms of the constructor function for foo. Am I correct to say that every proto of a function defaults to Function.prototype, which uses Object.prototype to create an object? The part that is confusing for me is Foo.prototype, when was this prototype created? Does a constructor function always default to the creation of a prototype which a constructor reference set back to itself and a proto set to object?
No wonder there is confusion. The picture is misleading to the point of being incorrect!
Objects created by calling a constructor function with the new keyword have their inheritance chain set to start with the prototype property of the constructor (correct in the picture).
The prototype property is created every time a function is declared using the function keyword to cover the case of the function being use as a constructor later - so you don't need to specify if a function is a constructor or not. For completeness, functions generated by the class keyword also have a prototype property.)
The function's prototype property's constructor property is set to the function when the prototype property is created (meaning when the function is declared). Again the picture is correct: the value of Foo.prototype.constructor is a reference to Foo.
What is wrong in the picture is objects a and b somehow joining together in a reverse fork and their properties becoming available to instances of Foo.
constructor is always an inherited property. If you replace the original prototype property of a function object with another object, you replace the constructor property inherited by objects constructed with the function. Although you can reset the constructor property of a functions prototype property, it's reasonably unusual and not a part of the story the picture is presenting.
If you do modify the inheritance chain by changing a function's prototype property value, the inheritance chain is still always a single threaded chain back to Object.prototype and then null. The inheritance chain never forks as shown in the picture. If you modified Foo.prototype in the picture to make it a or b, the constructor property of Foo instances would not be Foo.
The picture requires a lot of explanation to be useful.
The properties are assigned in the construction function. Any function can be used with new,thus becoming the "construction function".
var f = function(){};
var fInstance = new f();
console.log(fInstance.constructor); // *f*
If there are no properties assigned in that function (using this.propertyName), then the constructed instance will not have properties. If it does, then it will.
// No properties
var f = function(){};
// Two constructor properties, and one default property
var f = function(prop1, prop2){
this.name = prop1;
this.description = prop2;
this.something = "default";
};
If the prototype of the construction function has properties or methods (basically just glorified properties) attached to its prototype, then each instance will have those.
// No prototype
var f = function(){};
// Prototype with one method
var f = function(){};
f.prototype.test = function(){ console.log("hello"); };
The prototypes and properties must be manually created, and may or may not exist. By default, since using new requires a function, there will always be a constructor function. The process of instantiation using new will also always assign the prototype of the constructor to an object containing the constructing function as a property named constructor as well as all of the properties/methods of the construction function's prototype.
In this case, foo is a constructor function and B and C are objects.
Functions are also objects. Everything are objects. unlike classical inheritance where what defined objects are separate entities. Here an object that is an instance of Function is the constructor that will create an instance of its kind that inherits whatever object is on the constructors prototype attribute.
I am very confused, first off when you create an object does it
always come with the properties and proto? Is that the default?
Only way to get the objects own property y is if the constructor function sets this.y. If a property is not found on the object the system will continue to look at the object that was on the constructors prototype field. Some implementations has this as __proto__ but that is not a requirement. It is implementation specific how it is stored on the instance.
Also in terms of the constructor function for foo. Am I correct to say
that every proto of a function defaults to Function.prototype, which
uses Object.prototype to create an object?
function() {...} makes an instance of the constructor Function. All objects except Object itself inherits Object either indirectly or directly, including Function. Basically you can make a function like this:
var f = new Function('a', 'b', 'return a + b');
f is an instance of Function, as you can see. This is almost the same as:
var f = function(a, b) { return a + b; };
Now the first allows for text to be interpreted as code so its less efficient, but I imagine that in the early days these two would be identical in terms of interpretation. Modern engines prefer the last one since it is more predictable while the first can be seen as a specialized eval.
The part that is confusing for me is Foo.prototype, when was this
prototype created? Does a constructor function always default to the
creation of a prototype which a constructor reference set back to
itself and a proto set to object?
Yes. When the function Foo is created, JS creates by default protoype as new Object(), then it sets constructor to itself. The rest needs to be done in the code itself so we know there is something like this after the actual function code to do the rest of the class:
Foo.prototype.x = 10;
Foo.prototype.calculate = function(...) {...};

Is there a difference between constructor and constructor function in javascript?

I come from a Java background, completely understand what constructor does in java. I am new to javascript and trying to understand why a constructor is called constructor function. Do constructors and constructor functions mean different things in javascript ?
A constructor in JavaScript is a function that is used to construct an object. For example:
function Obj() {
// The constructed object is bound to the 'this' variable
this.property = "someValue";
}
var obj = new Obj();
console.log(obj.property); // Will print "someValue"
console.log(obj.constructor); // Will print Obj's code
Obj is now the constructor of the instance obj. Obj is just a normal function, but since it's invoked via new it acts as a constructor.
Note that constructor functions are by convention named like Java classes, i.e. Upper CamelCase. The language doesn't enforce it in any way, but it makes it clear that a function is intended as a constructor.
You can also achieve inheritance in JavaScript, even though the language lacks classes per se, by defining constructors' "prototypes":
// Base constructor, like a baseclass in Java
function Base() {
this.baseProperty = "baseValue";
}
// Base implementation of a method
Base.prototype.printSelf = function () {
console.log(this.baseProperty);
};
// Constructor, corresponding to a subclass in Java
function Obj() {
// Call "baseclass" constructor
Base.call(this);
this.property = "someValue";
}
// Inherit prototype from Base
Obj.prototype = Object.create(Base.prototype);
// Overload printSelf
Obj.prototype.printSelf = function () {
// Call base implementation
Base.prototype.printSelf.call(this);
console.log(this.property);
};
var obj = new Obj();
obj.printSelf();
See my fiddle for a live demonstration if you like.
Java constructors are special functions that can only be called at object creation; JavaScript "constructors" are just standard functions.
JS has no special handling or type called function constructor. It's a term used to imply that this function is used with the new keyword to create an object. Any function can be a "function constructor" by prefixing it with the new keyword.
Of course that is usually not the intention of the author. So the convention is to uppercase the first letter of the function name to denote that is a function constructor and should therefore be used in conjuction w/ new.
The term constructor is usually meant to mean function constructor. Most in the community use the term full term since JS has no classes, and function constructor is more clear.

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