Comment fonctionne JavaScript.prototype?




javascript prototype tutorial (17)

0) Deux choses différentes peuvent être appelées "prototype":

  • la propriété prototype, comme dans obj.prototype

  • la propriété interne du prototype, appelée [[Prototype]] dans ES5 .

    Il peut être récupéré via l' Object.getPrototypeOf() ES5 Object.getPrototypeOf() .

    Firefox le rend accessible via la propriété __proto__ en tant qu'extension. ES6 mentionne maintenant certaines exigences optionnelles pour __proto__ .

1) Ces concepts existent pour répondre à la question:

Quand je fais obj.property , où JS cherche-t-il .property ?

Intuitivement, l'héritage classique devrait affecter la recherche de propriété.

2)

  • __proto__ est utilisé pour le point . recherche de propriété comme dans obj.property .
  • .prototype n'est pas utilisé pour la recherche directement, seulement indirectement car il détermine __proto__ à la création de l'objet avec new .

L'ordre de recherche est:

  • Propriétés obj ajoutées avec obj.p = ... ou Object.defineProperty(obj, ...)
  • propriétés de obj.__proto__
  • propriétés de obj.__proto__.__proto__ , et ainsi de suite
  • si __proto__ est null , retourne undefined .

C'est la chaîne dite de prototype .

Vous pouvez éviter . recherche avec obj.hasOwnProperty('key') et Object.getOwnPropertyNames(f)

3) Il existe deux façons principales de définir obj.__proto__ :

  • new :

    var F = function() {}
    var f = new F()
    

    alors new a fixé:

    f.__proto__ === F.prototype
    

    C'est là que .prototype est utilisé.

  • Object.create :

     f = Object.create(proto)
    

    ensembles:

    f.__proto__ === proto
    

4) Le code:

var F = function() {}
var f = new F()

Correspond au diagramme suivant:

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

Ce diagramme montre de nombreux nœuds d'objets prédéfinis: null , Object , Object.prototype , Function et Function.prototype . Nos 2 lignes de code n'ont créé que f , F et F.prototype .

5). .constructor vient normalement de F.prototype travers le . Chercher:

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

Lorsque nous écrivons f.constructor , JavaScript fait le . recherche en tant que:

  • f n'a pas de .constructor
  • f.__proto__ === F.prototype a .constructor === F , alors prends-le

Le résultat f.constructor == F est intuitivement correct, puisque F est utilisé pour construire f , par exemple définir des champs, un peu comme dans les langages OOP classiques.

6) La syntaxe de l'héritage classique peut être obtenue en manipulant des chaînes de prototypes.

ES6 ajoute la class et extends mots extends clés, qui sont simplement de la syntaxe en sucre pour une folie de manipulation de prototype auparavant possible.

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.
(new C(1)).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

Diagramme simplifié sans tous les objets prédéfinis:

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

Je ne suis pas dans les langages de programmation dynamiques, mais j'ai écrit ma juste part de code JavaScript. Je n'ai jamais vraiment eu la tête autour de cette programmation basée sur un prototype, est-ce que quelqu'un sait comment cela fonctionne?

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

Je me souviens de beaucoup de discussions que j'ai eues avec des gens il y a quelque temps (je ne suis pas sûr de ce que je fais), mais si je comprends bien, il n'y a pas de concept de classe. C'est juste un objet, et les instances de ces objets sont des clones de l'original, n'est-ce pas?

Mais quel est le but exact de cette propriété .prototype en JavaScript? Comment cela se rapporte-t-il à l'instanciation des objets?

modifier

Ces slides vraiment beaucoup aidé à comprendre ce sujet.


Consider the following keyValueStore object :

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

I can create a new instance of this object by doing this :

kvs = keyValueStore.create();

Each instance of this object would have the following public properties :

  • data
  • get
  • set
  • delete
  • getLength

Now, suppose we create 100 instances of this keyValueStore object. Even though get , set , delete , getLength will do the exact same thing for each of these 100 instances, every instance has its own copy of this function.

Now, imagine if you could have just a single get , set , delete and getLength copy, and each instance would reference that same function. This would be better for performance and require less memory.

That's where prototypes come in. A prototype is a "blueprint" of properties that is inherited but not copied by instances. So this means that it exists only once in memory for all instances of an object and is shared by all of those instances.

Now, consider the keyValueStore object again. I could rewrite it like this :

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

This does EXACTLY the same as the previous version of the keyValueStore object, except that all of its methods are now put in a prototype. What this means, is that all of the 100 instances now share these four methods instead of each having their own copy.


Let me tell you my understanding of prototypes. I am not going to compare the inheritance here with other languages. I wish people would stop comparing languages, and just understand the language as itself. Understanding prototypes and prototypal inheritance is so simple, as I will show you below.

Prototype is like a model, based on which you create a product. The crucial point to understand is that when you create an object using another object as it's prototype, the link between the prototype and the product is ever-lasting. Par exemple:

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

Every object contains an internal property called the [[prototype]], which can be accessed by the Object.getPrototypeOf() function. Object.create(model) creates a new object and sets it's [[prototype]] property to the object model . Hence when you do Object.getPrototypeOf(product) , you will get the object model .

Properties in the product are handled in the following way:

  • When a property is accessed to just read it's value, its looked up in the scope chain. The search for the variable starts from the product upwards to it's prototype. If such a variable is found in the search, the search is stopped right there, and the value is returned. If such a variable cannot be found in the scope chain, undefined is returned.
  • When a property is written(altered), then the property is always written on the product object. If the product does not have such a property already, it is implicitly created and written.

Such a linking of objects using the prototype property is called prototypal inheritance. There, it is so simple, agree?


Après avoir lu ce fil, je me sens confus avec Javascript Prototype Chain, puis j'ai trouvé ces graphiques

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance

c'est un graphique clair pour montrer l'héritage de JavaScript par chaîne de prototypes

et

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

celui-ci contient un exemple avec du code et plusieurs bons diagrammes.

chaîne de prototypes retombe finalement à Object.prototype.

La chaîne de prototypes peut être techniquement étendue aussi longtemps que vous le souhaitez, en plaçant à chaque fois le prototype de la sous-classe égal à un objet de la classe parente.

J'espère que cela vous sera utile pour comprendre JavaScript Prototype Chain.



Je joue un rôle en tant que professeur JavaScript et le concept de prototype a toujours été un sujet controversé à couvrir quand j'enseigne. Il m'a fallu un certain temps pour trouver une bonne méthode pour clarifier le concept, et maintenant dans ce texte, je vais essayer d'expliquer comment fonctionne JavaScript .prototype.

C'est un modèle d'objet basé sur un prototype très simple qui serait considéré comme un échantillon pendant l'explication, sans aucun commentaire pour le moment:

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

Il y a quelques points cruciaux que nous devons considérer avant de passer par le prototype.

1- Comment fonctionnent les fonctions JavaScript:

Pour faire le premier pas, nous devons comprendre, comment les fonctions JavaScript fonctionnent réellement, comme une fonction de classe en utilisant this mot this clé ou juste comme une fonction régulière avec ses arguments, ce qu'elle fait et ce qu'elle renvoie.

Disons que nous voulons créer un modèle d'objet Person . mais dans cette étape, je vais essayer de faire exactement la même chose sans utiliser le prototype et le new mot-clé .

Donc, dans cette étape, les functions , les objects et this mot this clé sont tout ce que nous avons.

La première question serait de savoir comment this mot this clé pourrait être utile sans utiliser un new mot-clé .

Donc, pour répondre à cela, disons que nous avons un objet vide, et deux fonctions comme:

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

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

et maintenant sans utiliser un new mot clé comment nous pourrions utiliser ces fonctions. Donc, JavaScript a 3 façons différentes de le faire:

une. La première façon consiste simplement à appeler la fonction comme une fonction régulière:

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

dans ce cas, il s'agirait de l'objet de contexte actuel, qui est généralement l'objet de window global dans le navigateur ou GLOBAL dans Node.js Cela signifie que nous aurions, window.name dans le navigateur ou GLOBAL.name dans Node.js, avec "George" comme valeur.

b. Nous pouvons les attacher à un objet, comme ses propriétés

- La façon la plus simple de le faire est de modifier l'objet person vide, comme:

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

De cette façon, nous pouvons les appeler comme:

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

et maintenant l'objet person est comme:

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

- L'autre façon d'attacher une propriété à un objet est d'utiliser le prototype de cet objet qui peut être trouvé dans n'importe quel objet JavaScript avec le nom de __proto__ , et j'ai essayé de l'expliquer un peu sur la partie récapitulative. Nous pourrions donc obtenir le résultat similaire en faisant:

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

Mais de cette façon, nous Object.prototype le Object.prototype , car chaque fois que nous créons un objet JavaScript en utilisant des littéraux ( { ... } ), il est créé en fonction de Object.prototype , ce qui signifie qu'il est attaché au nouveau object en tant qu'attribut nommé __proto__ , donc si nous le modifions, comme nous l'avons fait sur notre extrait de code précédent, tous les objets JavaScript seraient modifiés, ce qui n'est pas une bonne pratique. Alors, quelle pourrait être la meilleure pratique maintenant:

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

et maintenant d'autres objets sont en paix, mais cela ne semble toujours pas être une bonne pratique. Nous avons donc encore une solution, mais pour utiliser cette solution, nous devons revenir à cette ligne de code où l'objet person été créé ( var person = {}; ) puis le changer comme ceci:

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

ce qu'il fait est de créer un nouvel Object JavaScript et de lier l'objet propertiesObject à l'attribut __proto__ . Donc, pour vous assurer que vous pouvez faire:

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

Mais le point délicat ici est que vous avez accès à toutes les propriétés définies dans __proto__ sur le premier niveau de l'objet person (lisez la partie récapitulative pour plus de détails).

comme vous le voyez en utilisant l'une de ces deux façons, this pointerait exactement vers l'objet person .

c. JavaScript a un autre moyen de fournir la fonction avec this , qui utilise call ou apply pour appeler la fonction.

La méthode apply () appelle une fonction avec une valeur donnée et les arguments fournis sous la forme d'un tableau (ou d'un objet de type tableau).

et

La méthode call () appelle une fonction avec une valeur donnée et les arguments fournis individuellement.

De cette façon, qui est mon préféré, nous pouvons facilement appeler nos fonctions comme:

Person.call(person, "George");

ou

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

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

ces 3 méthodes sont les étapes initiales importantes pour comprendre la fonctionnalité .prototype.

2- Comment fonctionne le new mot-clé?

C'est la deuxième étape pour comprendre la fonctionnalité .prototype . C'est ce que j'utilise pour simuler le processus:

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

Dans cette partie, je vais essayer de prendre toutes les mesures que JavaScript prend, sans utiliser le new mot-clé et le prototype , lorsque vous utilisez un new mot-clé. donc quand nous faisons une new Person("George") , la fonction Person sert de constructeur. Voici ce que fait JavaScript, un par un:

une. tout d'abord, il fait un objet vide, essentiellement un hachage vide comme:

var newObject = {};

b. la prochaine étape que JavaScript prend est de joindre tous les objets prototypes à l'objet nouvellement créé

nous avons ici my_person_prototype similaire à l'objet prototype.

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

Ce n'est pas la façon dont JavaScript attache réellement les propriétés qui sont définies dans le prototype. La manière réelle est liée au concept de chaîne prototype.

une. & b. Au lieu de ces deux étapes, vous pouvez avoir exactement le même résultat en faisant:

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"

maintenant nous pouvons appeler la fonction getName dans notre my_person_prototype :

newObject.getName();

c. alors il donne cet objet au constructeur,

nous pouvons le faire avec notre échantillon comme:

Person.call(newObject, "George");

ou

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

alors le constructeur peut faire ce qu'il veut, parce que cet intérieur de ce constructeur est l'objet qui vient d'être créé.

maintenant le résultat final avant de simuler les autres étapes: Object {name: "George"}

Résumé:

Fondamentalement, lorsque vous utilisez le nouveau mot-clé sur une fonction, vous appelez cela et cette fonction sert de constructeur, donc quand vous dites:

new FunctionName()

JavaScript crée en interne un objet, un hachage vide puis il donne cet objet au constructeur, alors le constructeur peut faire ce qu'il veut, parce que cet intérieur de ce constructeur est l'objet qui vient d'être créé et ensuite il vous donne cet objet bien sûr si vous n'avez pas utilisé l'instruction return dans votre fonction ou si vous avez return undefined; un return undefined; à la fin de votre corps de fonction.

Ainsi, lorsque JavaScript recherche une propriété sur un objet, la première chose à faire est de la rechercher sur cet objet. Et puis il y a une propriété secrète [[prototype]] que nous avons habituellement comme __proto__ et cette propriété est ce que JavaScript regarde ensuite. Et quand il regarde à travers le __proto__ , dans la mesure où c'est encore un autre objet JavaScript, il a son propre attribut __proto__ , il monte et monte jusqu'à ce que le prochain __proto__ soit nul. Le point est le seul objet en JavaScript que son attribut __proto__ est nul est objet Object.prototype :

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

et c'est comme ça que l'héritage fonctionne en JavaScript.

En d'autres termes, lorsque vous avez une propriété prototype sur une fonction et que vous appelez une nouvelle sur celle-ci, après que JavaScript a fini de regarder cet objet nouvellement créé pour les propriétés, elle va regarder le .prototype la fonction et il est possible que cet objet a son propre prototype interne. etc.


There's two distinct but related entities here that need explaining:

  • The .prototype property of functions.
  • The [[Prototype]] [1] property of all objects [2] .

These are two different things.

The [[Prototype]] property:

This is a property that exists on all [2] objects.

What's stored here is another object, which, as an object itself, has a [[Prototype]] of its own that points to another object. That other object has a [[Prototype]] of its own. This story continues until you reach the prototypical object that provides methods that are accessible on all objects (like .toString ).

The [[Prototype]] property is part of what forms the [[Prototype]] chain. This chain of [[Prototype]] objects is what is examined when, for example, [[Get]] or [[Set]] operations are performed on an object:

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

The .prototype property:

This is a property that is only found on functions. Using a very simple function:

function Bar(){};

The .prototype property holds an object that will be assigned to b.[[Prototype]] when you do var b = new Bar . You can easily examine this:

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

One of the most important .prototype s is that Object.prototype . This prototype holds the prototypical object that all [[Prototype]] chains contain. On it, all the available methods for new objects are defined:

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

Now, since .prototype is an object, it has a [[Prototype]] property. When you don't make any assignments to Function.prototype , the .prototype 's [[Prototype]] points to the prototypical object ( Object.prototype ). This is automatically performed anytime you create a new function.

This way, any time you do new Bar; the prototype chain is set up for you, you get everything defined on Bar.prototype and everything defined on Object.prototype :

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

When you do make assignments to Function.prototype all you are doing is extending the prototype chain to include another object. It's like an insertion in a singly linked list.

This basically alters the [[Prototype]] chain allowing properties that are defined on the object assigned to Function.prototype to be seen by any object created by the function.

[1: Cela ne déroutera personne; mis à disposition via la __proto__propriété dans de nombreuses implémentations.
[2]: Tous sauf null.


C'est juste que vous avez déjà un objet avec Object.new mais vous n'avez toujours pas d'objet lors de l'utilisation de la syntaxe du constructeur.


When a constructor creates an object, that object implicitly references the constructor's “prototype” property for the purpose of resolving property references. The constructor's “prototype” property can be referenced by the program expression constructor.prototype, and properties added to an object's prototype are shared, through inheritance, by all objects sharing the prototype.


I found it helpful to explain the "prototype chain" as recursive convention when obj_n.prop_X is being referenced:

if obj_n.prop_X doesn't exist, check obj_n+1.prop_X where obj_n+1 = obj_n.[[prototype]]

If the prop_X is finally found in the k-th prototype object then

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

You can find a graph of the relation of Javascript objects by their properties here:

http://jsobjects.org


Chaque objet possède une propriété interne, [[Prototype]], le liant à un autre objet:

object [[Prototype]] -> anotherObject

En javascript traditionnel, l'objet lié est la propriété prototype d'une fonction:

object [[Prototype]] -> aFunction.prototype

Certains environnements exposent [[Prototype]] comme __proto__ :

anObject.__proto__ === anotherObject

Vous créez le lien [[Prototype]] lors de la création d'un objet.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

Donc, ces déclarations sont équivalentes:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

Une new instruction n'affiche pas la cible de lien ( Object.prototype ) elle-même; à la place, la cible est impliquée par le constructeur ( Object ).

Rappelles toi:

  • Chaque objet a un lien, [[Prototype]], parfois exposé comme __proto__ .
  • Chaque fonction a une propriété prototype .
  • Les objets créés avec new sont liés à la propriété prototype de leur constructeur.
  • Si une fonction n'est jamais utilisée en tant que constructeur, sa propriété prototype sera inutilisée.
  • Si vous n'avez pas besoin d'un constructeur, utilisez Object.create au lieu de new .

Dans une langue implémentant l'héritage classique comme Java, C # ou C ++, vous commencez par créer une classe - un plan pour vos objets - et ensuite vous pouvez créer de nouveaux objets de cette classe ou vous pouvez étendre la classe, définissant une nouvelle classe qui augmente la classe originale.

En JavaScript vous créez d'abord un objet (il n'y a pas de concept de classe), alors vous pouvez augmenter votre propre objet ou en créer de nouveaux objets. Ce n'est pas difficile, mais un peu étranger et difficile à métaboliser pour quelqu'un d'habitué.

Exemple:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

Jusqu'à présent, j'étendais l'objet de base, maintenant je crée un autre objet et hérite ensuite de 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());

var Person = function (name) {
    this.name = name;
};
Person.prototype.getName = function () {
    return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
    this.name = name;
};
Customer.prototype = new Person();

var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
    return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Bien que comme je l'ai dit je ne peux pas appeler setAmountDue (), getAmountDue () sur une personne.

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

Chaque objet JavaScript a une propriété interne appelée [[Prototype]] . Si vous recherchez une propriété via obj.propName ou obj['propName'] et que l'objet n'a pas cette propriété - qui peut être vérifiée via obj.hasOwnProperty('propName') - le moteur d'exécution recherche la propriété dans l'objet référencé par [[Prototype]] à la place. Si l'objet-prototype n'a pas non plus cette propriété, son prototype est vérifié à son tour, marchant ainsi sur la chaîne prototype de l'objet original jusqu'à ce qu'une correspondance soit trouvée ou que sa fin soit atteinte.

Certaines implémentations JavaScript permettent un accès direct à la propriété [[Prototype]], par exemple via une propriété non standard nommée __proto__ . En général, il est seulement possible de définir le prototype d'un objet lors de la création de l'objet: Si vous créez un nouvel objet via new Func() , la propriété [[Prototype]] de l'objet sera définie sur l'objet référencé par Func.prototype .

Cela permet de simuler des classes en JavaScript, bien que le système d'héritage de JavaScript soit - comme nous l'avons vu - prototypique, et non basé sur des classes:

Pensez simplement aux fonctions du constructeur en tant que classes et aux propriétés du prototype (c'est-à-dire de l'objet référencé par la propriété prototype la fonction constructeur) en tant que membres partagés, c'est-à-dire membres identiques pour chaque instance. Dans les systèmes basés sur les classes, les méthodes sont implémentées de la même manière pour chaque instance, les méthodes sont normalement ajoutées au prototype, tandis que les champs d'un objet sont spécifiques à l'instance et donc ajoutés à l'objet lui-même pendant la construction.



what is the exact purpose of this ".prototype" property?

The interface to standard classes become extensible. For example, you are using the Array class and you also need to add a custom serializer for all your array objects. Would you spend time coding up a subclass, or use composition or ... The prototype property solves this by letting the users control the exact set of members/methods available to a class.

Think of prototypes as an extra vtable-pointer. When some members are missing from the original class, the prototype is looked up at runtime.


It may help to categorise prototype chains into two categories.

Consider the constructor:

 function Person() {}

The value of Object.getPrototypeOf(Person) is a function. In fact, it is Function.prototype . Since Person was created as a function, it shares the same prototype function object that all functions have. It is the same as Person.__proto__ , but that property should not be used. Anyway, with Object.getPrototypeOf(Person) you effectively walk up the ladder of what is called the prototype chain.

The chain in upward direction looks like this:

PersonFunction.prototypeObject.prototype (end point)

Important is that this prototype chain has little to do with the objects that Person can construct . Those constructed objects have their own prototype chain, and this chain can potentially have no close ancestor in common with the one mentioned above.

Take for example this object:

var p = new Person();

p has no direct prototype-chain relationship with Person . Their relationship is a different one. The object p has its own prototype chain. Using Object.getPrototypeOf , you'll find the chain is as follows:

pPerson.prototypeObject.prototype (end point)

There is no function object in this chain (although that could be).

So Person seems related to two kinds of chains, which live their own lives. To "jump" from one chain to the other, you use:

  1. .prototype : jump from the constructor's chain to the created-object's chain. This property is thus only defined for function objects (as new can only be used on functions).

  2. .constructor : jump from the created-object's chain to the constructor's chain.

Here is a visual presentation of the two prototype chains involved, represented as columns:

To summarise:

The prototype property gives no information of the subject's prototype chain, but of objects created by the subject.

It is no surprise that the name of the property prototype can lead to confusion. It would maybe have been clearer if this property had been named prototypeOfConstructedInstances or something along that line.

You can jump back and forth between the two prototype chains:

Person.prototype.constructor === Person

This symmetry can be broken by explicitly assigning a different object to the prototype property (more about that later).

Create one Function, Get Two Objects

Person.prototype is an object that was created at the same time the function Person was created. It has Person as constructor, even though that constructor did not actually execute yet. So two objects are created at the same time:

  1. The function Person itself
  2. The object that will act as prototype when the function is called as a constructor

Both are objects, but they have different roles: the function object constructs , while the other object represents the prototype of any object that function will construct. The prototype object will become the parent of the constructed object in its prototype chain.

Since a function is also an object, it also has its own parent in its own prototype chain, but recall that these two chains are about different things.

Here are some equalities that could help grasp the issue -- all of these print true :

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

Adding levels to the prototype chain

Although a prototype object is created when you create a constructor function, you can ignore that object, and assign another object that should be used as prototype for any subsequent instances created by that constructor.

Par exemple:

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

Now the prototype chain of t is one step longer than that of p :

tpPerson.prototypeObject.prototype (end point)

The other prototype chain is not longer: Thief and Person are siblings sharing the same parent in their prototype chain:

Person }
Thief } → Function.prototypeObject.prototype (end point)

The earlier presented graphic can then be extended to this (the original Thief.prototype is left out):

The blue lines represent prototype chains, the other coloured lines represent other relationships:

  • between an object and its constructor
  • between a constructor and the prototype object that will be used for constructing objects

prototype vous permet de faire des classes. Si vous n'utilisez pas de prototype il devient statique.

Voici un petit exemple.

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

Dans le cas ci-dessus, vous avez un test d'appel de fonction statique. Cette fonction n'est accessible que par obj.test où vous pouvez imaginer que obj est une classe.

où comme dans le code ci-dessous

function obj()
{
}

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

L'obj est devenu une classe qui peut maintenant être instanciée. Plusieurs instances d'obj peuvent exister et toutes ont la fonction de test .

Ce qui précède est ma compréhension. J'en fais un wiki communautaire, donc les gens peuvent me corriger si j'ai tort.





prototype-oriented