What Does It Mean That JavaScript Is a Prototype Based Language

What does it mean that Javascript is a prototype based language?

Prototypal inheritance is a form of object-oriented code reuse. Javascript is one of the only [mainstream] object-oriented languages to use prototypal inheritance. Almost all other object-oriented languages are classical.

In classical inheritance, the programmer writes a class, which defines an object. Multiple objects can be instantiated from the same class, so you have code in one place which describes several objects in your program. Classes can then be organized into a hierarchy, furthering code reuse. More general code is stored in a higher-level class, from which lower level classes inherit. This means that an object is sharing code with other objects of the same class, as well as with its parent classes.

In the prototypal inheritance form, objects inherit directly from other objects. All of the business about classes goes away. If you want an object, you just write an object. But code reuse is still a valuable thing, so objects are allowed to be linked together in a hierarchy. In javascript, every object has a secret link to the object which created it, forming a chain. When an object is asked for a property that it does not have, its parent object will be asked... continually up the chain until the property is found or until the root object is reached.

Each function in JavaScript (which are objects themselves) actually has a member called "prototype", which is responsible for providing values when an object is asked for them. Having this member allows the constructor mechanism (by which objects are constructed from functions) to work. Adding a property to the prototype of a function object will make it available to the constructed object, as well as to all of the objects which inherit from it.

Advantages

There may not be a hard and fast rule as to why prototypal inheritance is an advantageous form of code-reuse. Code reuse itself is advantageous, and prototypal inheritance is a sensible way of going about it. You might argue that prototypal inheritance is a fairly simple model of code reuse, and that code can be heavily reused in direct ways. But classical languages are certainly able to accomplish this as well.

Sidenote: @Andrew Hedges makes a good point, that there are actually many prototypal languages. It's worth noting that these others exist, but also worth noting that none of them are anything close to mainstream. NewtonScript seemed to have some traction for a while, but died with its platform. It's also possible to extend some modern languages in ways which add prototypal capabilities.

What are the advantages that prototype based OO has over class based OO?

The advantage of prototypal inheritance is that it potentially allows fancy metaprogramming in a straightforward way because the prototype chain is easily manipulated. This is a rather academic advantage because metaprogramming is the wrong answer 99% of the time. As an example, you could have a Javascript Key-Value Observer style data manipulation layer with a special DSL that transparently switched between a local SQLite backing when offline and a REST based server store when online via prototype swapping. I'm not sure it's the best way to do this, but it's the best I can come up with this late. It's not the sort of thing you generally want to do in project code since this sort of indirection is hell to debug once you start getting it going on multiple layers, but it's not bad when you keep it in a library.

Another less helpful advantage is that it allows you to design your own class system. I say less helpful because more or less all javascript libraries have their own slightly incompatible approach to how 'classes' are put together.

There are a lot of people replying who are mixing the inheritance model with the languages implemented in that model. The fact that javascript is dynamic and weakly typed and thus hard to tool has nothing to do with it being a prototypal language.

prototypal inheritance concept in javascript as a prototype based language

Unlike most other object-oriented languages, JavaScript doesn’t actually have a concept
of classes. In most other object-oriented languages you would instantiate an instance of a particular class, but that is not the case in JavaScript.

In JavaScript, objects can create new objects, and objects can inherit from other objects.
This whole concept is called prototypal inheritance.

but how we can make an object?

Simply you can create a generic object with {}.

var a = {};
a.prop = "myprop";
console.log(a); //Object { prop="myprop" }

you cannot create instance of a because it is not a function. in other words it has not special internal method [[Construct]].

In JavaScript any function can also be instantiated as an object. The function below is a simple function which takes a name and saves it to the current context:

function User( name ) {
this.name = name;
}

We can see that User is instance of Function:

alert(User instanceof Function); //true

Create a new instance of that function, with the specified name:

var me = new User( "My Name" ); 

We can see that its name has been set as a property of itself:

alert( me.name == "My Name" ); //true

And that it is an instance of the User object:

alert( me.constructor == User ); //true

Now, since User() is just a function, what happens when we treat it as such?

User( "Test" );

Since its this context wasn't set, it defaults to the global window object, meaning that window.name is equal to the name provided:

alert( window.name == "Test" ); //true

The constructor property exists on every object and will always point back to the function that created it. This way, you should be able to effectively duplicate the object, creating a new one of the same base class but not with the same properties. An example of this can be seen below:

var you = new me.constructor();

We can see that the constructors are, in fact, the same:

alert( me.constructor == you.constructor ); //true

Prototype And Public Methods

Prototype simply contains an object that will act as a base reference for all new copies of its parent object. Essentially, any property of the prototype will be available on every instance of that object. This creation/reference process gives us a cheap version of inheritance.

Since an object prototype is just an object, you can attach new properties to them, just like any other object. Attaching new properties to a prototype will make them a part of every object instantiated from the original prototype, effectively making all the properties public. example:

function User( name, age ){
this.name = name;
this.age = age;
}

Adding methods and properties to the prototype property of the constructor function is another way to add functionality to the objects this constructor produces. Let's add one more property, CardNo and a getName() method:

User.prototype.CardNo='12345';
User.prototype.getName = function(){
return this.name;
};

And add another function to the prototype. Notice that the context is going to be within the instantiated object.

User.prototype.getAge = function(){
return this.age;
};

Instantiate a new User object:

var user = new User( "Bob", 44 );

We can see that the two methods we attached are with the object, with proper contexts:

alert( user.getName() == "Bob" ); //true
alert( user.getAge() == 44 ); //true

So every function in javascript has a prototype property. Its initial value is an empty object ({}). Notice that generic objects (not functions) don't have the prototype property:

alert( user.prototype ); //undefined (and it is not useful even you define it)

Delegation

When you try to access a property of user, say user.name the JavaScript engine will look through all of the properties of the object searching for one called name and, if it finds it, will return its value:

alert( user.name );

What if the javascript engine cannot find the property? It will identify the prototype of the constructor function used to create this object (same as if you do user.constructor.prototype). If the property is found in the prototype, this property is used:

alert(user.CardNo); // "12345"

and so...

If you want to distinguish between the object's own properties versus the prototype's properties, use hasOwnProperty(). Try:

alert( user.hasOwnProperty('name') ); //true
alert( user.hasOwnProperty('CardNo') ); //false

Private Methods

When you directly set a property for a function, it will be private. example:

function User()
{
var prop="myprop";
function disp(){
alert("this is a private function!");
}
}
var we = new User();
alert(we.prop); //undefined
we.disp(); // Fails, as disp is not a public property of the object

Privileged Methods

Privileged methods is a term coined by Douglas Crockford to refer to methods that are able
to view and manipulate private variables (within an object) while still being accessible to
users as a public method. example:

Create a new User object constructor:

function User( name, age ) {
//Attempt to figure out the year that the user was born:
var year = (new Date()).getFullYear() – age;

//Create a new Privileged method that has access to the year variable, but is still publically available:
this.getYearBorn = function(){
return year;
};
}

Create a new instance of the user object:

var user = new User( "Bob", 44 );

Verify that the year returned is correct:

alert( user.getYearBorn() == 1962 ); //true

And notice that we're not able to access the private year property of the object:

alert( user.year == null ); //true

In essence, privileged methods are dynamically generated methods, because they’re added
to the object at runtime, rather than when the code is first compiled. While this technique is computationally more expensive than binding a simple method to the object prototype, it is also much more powerful and flexible.

Static Methods

The premise behind static methods is virtually identical to that of any other normal function. The primary difference, however, is that the functions exist as static properties of an object. As a property, they are not accessible within the context of an instance of that object; they are only available in the same context as the main object itself. For those familiar with traditional classlike inheritance, this is sort of like a static class method.

In reality, the only advantage to writing code this way is to keep object namespaces clean.

A static method attached to the User object:

function User(){}
User.cloneUser = function( user ) {
//Create, and return, a new user
return new User( user.getName(), user.getAge() );
};

The cloneUser function is only accessible by User:

var me = new User();
me.cloneUser(me); //Uncaught TypeError: Object #<User> has no method 'cloneUser'

The difference between a class-based language (like Java or Python) and a prototype-based language (like Javascript)?

It seems like you're familiar with the actual languages, so you know what the difference is, right? I guess you're asking about the differences at a deeper, maybe more "philosophical", level.

Class-based languages tend to work from the top down, general to particular. The classic example would be where you define a 'Vehicle' class, and then subclasses like 'Car', 'Train'.

A prototype-based language would instead tend to start with the particular, in fact start with an instance of the particular and modify that.

I like this: http://steve-yegge.blogspot.ie/2008/10/universal-design-pattern.html

In the end it's not a question of if you can do inheritance in JS or whether there is something that you can do in one language but not the other. It's a deep difference in their ways of approaching problem solving. For a particular problem a good idiomatic solution that made best use of the language's features would probably be quite different in a prototype-based language from one in a class-based language.

prototype based vs. class based inheritance

There are about a hundred terminology issues here, mostly built around someone (not you) trying to make their idea sound like The Best.

All object oriented languages need to be able to deal with several concepts:

  1. encapsulation of data along with associated operations on the data, variously known as data members and member functions, or as data and methods, among other things.
  2. inheritance, the ability to say that these objects are just like that other set of objects EXCEPT for these changes
  3. polymorphism ("many shapes") in which an object decides for itself what methods are to be run, so that you can depend on the language to route your requests correctly.

Now, as far as comparison:

First thing is the whole "class" vs "prototype" question. The idea originally began in Simula, where with a class-based method each class represented a set of objects that shared the same state space (read "possible values") and the same operations, thereby forming an equivalence class. If you look back at Smalltalk, since you can open a class and add methods, this is effectively the same as what you can do in Javascript.

Later OO languages wanted to be able to use static type checking, so we got the notion of a fixed class set at compile time. In the open-class version, you had more flexibility; in the newer version, you had the ability to check some kinds of correctness at the compiler that would otherwise have required testing.

In a "class-based" language, that copying happens at compile time. In a prototype language, the operations are stored in the prototype data structure, which is copied and modified at run time. Abstractly, though, a class is still the equivalence class of all objects that share the same state space and methods. When you add a method to the prototype, you're effectively making an element of a new equivalence class.

Now, why do that? primarily because it makes for a simple, logical, elegant mechanism at run time. now, to create a new object, or to create a new class, you simply have to perform a deep copy, copying all the data and the prototype data structure. You get inheritance and polymorphism more or less for free then: method lookup always consists of asking a dictionary for a method implementation by name.

The reason that ended up in Javascript/ECMA script is basically that when we were getting started with this 10 years ago, we were dealing with much less powerful computers and much less sophisticated browsers. Choosing the prototype-based method meant the interpreter could be very simple while preserving the desirable properties of object orientation.

Prototype based object orientation. The good, the bad and the ugly?

Prototype-based OO lends itself poorly to static type checking, which some might consider a bad or ugly thing. Prototype-based OO does have a standard way of creating new objects, you clone and modify existing objects. You can also build factories, etc.

I think what people like most (the "good") is that prototype-based OO is very lightweight and flexible, offering a very high power-to-weight ratio.

For tips on how to use prototype-based OO, a great place to start is the original Self paper on The Power of Simplicity.

How does JavaScript .prototype work?

Every JavaScript object has an internal "slot" called [[Prototype]] whose value is either null or an object. You can think of a slot as a property on an object, internal to the JavaScript engine, hidden from the code you write. The square brackets around [[Prototype]] are deliberate, and are an ECMAScript specification convention to denote internal slots.

The value pointed at by the [[Prototype]] of an object, is colloquially known as "the prototype of that object."

If you access a property via the dot (obj.propName) or bracket (obj['propName']) notation, and the object does not directly have such a property (ie. an own property, checkable via obj.hasOwnProperty('propName')), the runtime looks for a property with that name on the object referenced by the [[Prototype]] instead. If the [[Prototype]] also does not have such a property, its [[Prototype]] is checked in turn, and so on. In this way, the original object's prototype chain is walked until a match is found, or its end is reached. At the top of the prototype chain is the null value.

Modern JavaScript implementations allow read and/or write access to the [[Prototype]] in the following ways:

  1. The new operator (configures the prototype chain on the default object returned from a constructor function),
  2. The extends keyword (configures the prototype chain when using the class syntax),
  3. Object.create will set the supplied argument as the [[Prototype]] of the resulting object,
  4. Object.getPrototypeOf and Object.setPrototypeOf (get/set the [[Prototype]] after object creation), and
  5. The standardized accessor (ie. getter/setter) property named __proto__ (similar to 4.)

Object.getPrototypeOf and Object.setPrototypeOf are preferred over __proto__, in part because the behavior of o.__proto__ is unusual when an object has a prototype of null.

An object's [[Prototype]] is initially set during object creation.

If you create a new object via new Func(), the object's [[Prototype]] will, by default, be set to the object referenced by Func.prototype.

Note that, therefore, all classes, and all functions that can be used with the new operator, have a property named .prototype in addition to their own [[Prototype]] internal slot. This dual use of the word "prototype" is the source of endless confusion amongst newcomers to the language.

Using new with constructor functions allows us to simulate classical inheritance in JavaScript; although JavaScript's inheritance system is - as we have seen - prototypical, and not class-based.

Prior to the introduction of class syntax to JavaScript, constructor functions were the only way to simulate classes. We can think of properties of the object referenced by the constructor function's .prototype property as shared members; ie. members which are the same for each instance. In class-based systems, methods are implemented the same way for each instance, so methods are conceptually added to the .prototype property; an object's fields, however, are instance-specific and are therefore added to the object itself during construction.

Without the class syntax, developers had to manually configure the prototype chain to achieve similar functionality to classical inheritance. This led to a preponderance of different ways to achieve this.

Here's one way:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
return child;
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

...and here's another way:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
function tmp() {}
tmp.prototype = parent.prototype
const proto = new tmp()
proto.constructor = child
child.prototype = proto
return child
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

The class syntax introduced in ES2015 simplifies things, by providing extends as the "one true way" to configure the prototype chain in order to simulate classical inheritance in JavaScript.

So, similar to the code above, if you use the class syntax to create a new object like so:

class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}

const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

...the resulting object's [[Prototype]] will be set to an instance of Parent, whose [[Prototype]], in turn, is Parent.prototype.

Finally, if you create a new object via Object.create(foo), the resulting object's [[Prototype]] will be set to foo.



Related Topics



Leave a reply



Submit