Coder Perfect

What is the purpose of JavaScript.prototype?

Problem

Although I’m not a big fan of dynamic programming languages, I’ve written a lot of JavaScript code. I’ve never quite grasped the concept of prototype-based programming; does anyone know how it works?

var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

I recall a lot of discussion I had with individuals a while back (I’m not sure what I’m doing), but there is no concept of a class, as far as I can tell. Isn’t it just an object, and instances of that object are just clones of the original?

But what exactly is the purpose of JavaScript’s “.prototype” property? What does this have to do with instantiating objects?

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

Also, these slides were really useful.

Asked by John Leidegren

Solution #1

In a language that implements traditional inheritance, such as Java, C#, or C++, you start by creating a class—a blueprint for your objects—and then you can expand the class by declaring a new class that augments the original class.

In JavaScript, you build an object first (there is no concept of a class), then alter it or generate additional objects from it. It’s not difficult, but it’s unfamiliar and difficult to digest for someone used to the traditional method.

Example:

I’ve been extending the basic object till now; now I’m creating a new object and inheriting from Person.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

As previously stated, I am unable to call setAmountDue() or getAmountDue() on a Person.

//The following statement generates an error.
john.setAmountDue(1000);

Answered by stivlo

Solution #2

Every JavaScript object contains an internal “slot” named [[Prototype]], which might be null or an object. A slot is a property on an object that is hidden from the code you write and is internal to the JavaScript engine. The square brackets around [[Prototype]] are intentional and follow an ECMAScript convention for indicating internal slots.

The value pointed at by an object’s [[Prototype]] is referred to as “the prototype of that object.”

If you use the dot (obj.propName) or bracket (obj[‘propName’]) notation to access a property and the object does not have one (i.e. an own property, as determined by obj.hasOwnProperty(‘propName’)), the runtime looks for a property with that name on the object indicated by the [[Prototype]]. If the [[Prototype]] doesn’t contain such a property, the [[Prototype]] of that [[Prototype]] is tested, and so on. The prototype chain of the original item is so walked until a match is found or the end is reached. The null value is at the top of the prototype chain.

The [[Prototype]] can be read and/or written to in the following ways:

Because the behavior of o. proto is odd when an object has a prototype of null, Object.getPrototypeOf and Object.setPrototypeOf are preferred over proto .

The [[Prototype]] of an object is first set when it is created.

When you use new Func() to create a new object, the object’s [[Prototype]] is set to the object referenced by Func.prototype by default.

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 double meaning of the word “prototype” causes unending consternation among novices to the language.

We may emulate traditional inheritance in JavaScript by using new with constructor functions, despite the fact that JavaScript’s inheritance system is prototype and not class-based, as we’ve shown.

Constructor functions were the only way to imitate classes before JavaScript’s introduction of class syntax. Property of the object referred by the constructor function’s.prototype property can be thought of as shared members; that is, members that are the same for every instance. Methods are conceptually added to the.prototype property in class-based systems because they are implemented the same way for each instance; however, an object’s fields are instance-specific and are added to the object itself during construction.

Developers have to manually configure the prototype chain without the class syntax to get functionality akin to classical inheritance. As a result, there are a lot of various ways to do it.

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 to look at it:

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 new ES2015 class syntax makes things easier by introducing extends as the “one true way” to configure the prototype chain in JavaScript to emulate traditional inheritance.

If you use the class syntax to create a new object in the same way as the code above:

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

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

…the [[Prototype]] of the resulting object will be assigned to an instance of Parent, whose [[Prototype]] is Parent.prototype.

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

Answered by Christoph

Solution #3

This is a very basic prototype-based object model that will be used as an example during the explanation, with no further comment:

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

Before we go into the prototype concept, there are a few things we need to think about.

To begin, we must first understand how JavaScript functions work, whether as a class-like function with this keyword or as a conventional function with arguments, what it performs, and what it returns.

Let’s imagine we want to make a model of a person. However, in this stage, I’ll try to perform the same thing without utilizing prototype or the new keyword.

We only have functions, objects, and this keyword in this phase.

The first question is how this keyword can be useful without requiring the usage of a new term.

So, let’s pretend we have an empty object and two functions, such as:

var person = {};
function Person(name){  this.name = name;  }

function getName(){
    console.log(this.name);
}

How can we utilize these functions now without needing a new keyword? So there are three distinct ways to do it with JavaScript:

Person("George");
getName();//would print the "George" in the console

This is the current context object, which is normally the global window object in the browser or GLOBAL in Node.js in this case. It means we’d have “George” as the value of window.name in the browser or GLOBAL.name in Node.js.

-The simplest method is to alter the empty person object, like in:

person.Person = Person;
person.getName = getName;

We can refer to them in this manner:

person.Person("George");
person.getName();// -->"George"

Now the person object looks like this:

Object {Person: function, getName: function, name: "George"}

-Another approach to connect a property to an object is to use the object’s prototype, which can be found in any JavaScript object with the identifier __proto__, and I attempted to explain it a little in the summary section. As a result, we might achieve a comparable result by performing the following:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

But what we’re really doing here is changing Object.prototype, because whenever we create a JavaScript object with literals (… ), it’s based on Object.prototype, which means it’s attached to the newly created object as an attribute named __proto__, so if we change it, as we did in our previous code snippet, all the JavaScript objects will be changed as well, which isn’t a good practice. So, what is the better practice right now:

person.__proto__ = {
    Person: Person,
    getName: getName
};

Other items are now at ease, but it does not appear to be a good habit. So we have one more option, but in order to use it, we must return to the line of code where the person object was created (var person = 😉 and change it to:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

It creates a new JavaScript Object with the propertiesObject attached to the __proto__ attribute. So, to be sure you’re capable of:

console.log(person.__proto__===propertiesObject); //true

But here’s the catch: on the first level of the person object, you have access to all of the properties defined in __proto__ (read the summary part for more detail).

As you can see, each of these two methods will precisely point to the person object.

and

this way which is my favorite, we can easily call our functions like:

Person.call(person, "George");

or

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

These three approaches are the most crucial first stages in learning how to use.prototype.

This is the second stage in learning how to use.prototype. This is how I replicate the procedure:

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

In this section, I’ll attempt to perform all of the stages that JavaScript performs without utilizing the new keyword and prototype, which are used when the new keyword is used. As a result, when we call new Person(“George”), the Person function acts as a constructor. Here’s what JavaScript does one by one:

var newObject = {};

My person prototype is a prototype object like the prototype object.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

JavaScript does not actually attach the properties defined in the prototype in this manner. The real path is linked to the notion of the prototype chain.

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

In our my person prototype, we can now call the getName function:

newObject.getName();

With our example, we can accomplish the following:

Person.call(newObject, "George");

or

Person.apply(newObject, ["George"]);

The constructor can then do anything it wants because the object that was just created is contained within it.

before simulating the remaining steps, here’s the finished result: “George” is the name of the object.

When you use the new keyword on a function, you’re basically invoking it and it’s acting as a constructor, so when you say:

new FunctionName()

JavaScript internally makes an object, an empty hash and then it gives that object to the constructor, then the constructor can do whatever it wants, because this inside of that constructor is the object that was just created and then it gives you that object of course if you haven’t used the return statement in your function or if you’ve put a return undefined; at the end of your function body.

So the first thing JavaScript does when it wants to look up a property on an object is look it up on that object. Then there’s a hidden property called [[prototype]], which we generally refer to as __proto__, and it’s this property that JavaScript examines next. And when it looks through the __proto__, it goes up and up until it gets to the point where the next __proto__ is null, since it’s still another JavaScript object with its own __proto__ attribute. The Object.prototype object is the only object in JavaScript with a null __proto__ attribute:

console.log(Object.prototype.__proto__===null);//true

In JavaScript, inheritance operates in the same way.

In other words, if a function has a prototype property and you call new on it, JavaScript will look at the function’s.prototype after it has finished looking at the newly generated object for properties, and it is possible that this object has its own internal prototype. and so forth.

Answered by Mehran Hatami

Solution #4

Ciro San’s mind was calm and tranquil as he descended Mount Fire Fox after intense meditation.

His hand, on the other hand, was restless and grabbed a brush by itself, scribbling down the following notes.

0) Two different things can be called “prototype”:

1) Those notions exist in order to respond to the following question:

Classic inheritance should, on the surface, affect property lookup.

2)

Lookup order is:

The prototype chain is what it’s called.

You can stay away from it. With obj, you may do a lookup. Object and hasOwnProperty(‘key’). getOwnPropertyNames(f)

3) There are two basic methods for configuring obj. proto :

4) The code:

var F = function(i) { this.i = i }
var f = new F(1)

The following diagram corresponds to it (some Number stuff is omitted):

(Function)       (  F  )                                      (f)----->(1)
 |  ^             | | ^                                        |   i    |
 |  |             | | |                                        |        |
 |  |             | | +-------------------------+              |        |
 |  |constructor  | |                           |              |        |
 |  |             | +--------------+            |              |        |
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |  |             |                | +----------+              |        |
 |  |             |                | |                         |        |
 |  |             |                | | +-----------------------+        |
 |  |             |                | | |                                |
 v  |             v                v | v                                |
(Function.prototype)              (F.prototype)                         |
 |                                 |                                    |
 |                                 |                                    |
 |[[Prototype]]                    |[[Prototype]]          [[Prototype]]|
 |                                 |                                    |
 |                                 |                                    |
 | +-------------------------------+                                    |
 | |                                                                    |
 v v                                                                    v
(Object.prototype)                                       (Number.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

This diagram depicts a number of preset object nodes in the language:

Our 2 lines of code only created the following new objects:

Because you do: I is now a property of f.

var f = new F(1)

It evaluates F, returning this as the value of new, which is subsequently assigned to f.

5) .constructor normally comes from F.prototype through the . lookup:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

When we write f.constructor in JavaScript, it performs a. search as follows:

F is used to construct f, such as set fields, as in classic OOP languages, hence the result f.constructor == F is intuitively correct.

6) Using prototype chains, you may obtain traditional inheritance syntax.

ES6 introduces the class and extends keywords, which are basically syntactic sugar for previously unthinkable prototype modification.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
c = new C(1)
c.inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

Diagram simplified without any preset objects:

(c)----->(1)
 |   i
 |
 |
 |[[Prototype]]
 |
 |
 v    __proto__
(C)<--------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |[[Prototype]] 
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|[[Prototype]]    (D.prototype)--------> (inc2 function object)
| |                |             inc2
| |                |
| |                |[[Prototype]]
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)------->(inc function object)
|                inc
v
Function.prototype

Let’s take a look at how the following functions:

c = new C(1)
c.inc() === 2

As explained in “4),” the first line sets c.i to 1.

When we perform the following on the second line:

c.inc()

D.inc and d.inc2 are explained using the same rationale.

Additional implications of class worth knowing are mentioned in this article https://javascript.info/class#not-just-a-syntax-sugar. Some of them may be impossible to achieve without the class keyword (to be determined):

Answered by Ciro Santilli 新疆再教育营六四事件法轮功郝海东

Solution #5

You can create classes with prototype. It becomes a static if you don’t utilize prototype.

Here’s a quick illustration.

var obj = new Object();
obj.test = function() { alert('Hello?'); };

You have a static funcation call test in the example above. This function can only be accessed using the function obj.test, where obj is a class.

while in the code below

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

The obj has now been turned into a class that may be instantiated. There can be several instances of obj, each with the test function.

This is my understanding of the situation. I’m going to make it a community wiki so that others can correct me if I’m wrong.

Answered by 3 revs, 2 users 93%

Post is based on https://stackoverflow.com/questions/572897/how-does-javascript-prototype-work