Question Comment fonctionne JavaScript .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 .prototype propriété en JavaScript? Comment cela se rapporte-t-il à l'instanciation des objets?


modifier

Celles-ci glisse vraiment beaucoup aidé à comprendre ce sujet.


1856
2018-02-21 12:31


origine


Réponses:


Chaque objet JavaScript a une propriété interne appelée [[Prototype]]. Si vous recherchez une propriété via obj.propName ou obj['propName'] et l'objet n'a pas une telle 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 le prototype-objet ne possède pas non plus une telle propriété, son prototype est vérifié à son tour, marchant ainsi sur l'objet original chaîne prototype 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 fonction du constructeur prototype propriété) en tant que membres partagés, c'est-à-dire les membres qui sont les mêmes 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.


925
2018-02-21 13:33



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);

1755
2018-01-24 03:42



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, en tant que fonction de classe en utilisant this mot-clé dedans ou juste comme une fonction régulière avec ses arguments, ce qu'il fait et ce qu'il renvoie.

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

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

La première question serait Comment this mot-clé pourrait être utile sans utiliser 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 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, ce serait l'objet de contexte actuel, qui est généralement le global window objet 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 attacher à un objet, comme ses propriétés

-Le moyen le plus simple pour ce faire, modifie le vide person objet, comme:

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

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

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

et maintenant le person l'objet est comme:

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

-L'autre façon d'attacher une propriété à un objet utilise 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ésumée. Nous pourrions donc obtenir le résultat similaire en faisant:

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

Mais de cette façon, ce que nous faisons est en train de modifier la Object.prototype, parce que 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é à l'objet nouvellement créé en tant qu'attribut nommé __proto__ , donc si nous le changeons, 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 devrions revenir à cette ligne de code où person objet créé (var person = {};) puis changez comme:

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

ce qu'il fait est de créer un nouveau JavaScript Object et attachez le propertiesObject au __proto__ attribut. 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__ au premier niveau du person objet (lire la partie récapitulative pour plus de détails).


comme vous le voyez en utilisant l'un de ces deux moyens this pointerait exactement à la person objet.

c. JavaScript a un autre moyen de fournir la fonction avec this, qui utilise appel ou appliquer invoquer la fonction.

La méthode apply () appelle une fonction avec une valeur donnée et   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   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 le new mot-clé fonctionne?

c'est la deuxième étape pour comprendre le .prototype fonctionnalité.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 prototype, quand vous utilisez new mot-clé. alors quand on fait new Person("George"), Person La fonction 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 attacher tous les objets prototypes à l'objet nouvellement créé

nous avons my_person_prototype ici semblable à 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 le getName fonctionner 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 ce à l'intérieur de ce constructeur est l'objet qui vient d'être créé.

maintenant le résultat final avant de simuler les autres étapes:     Objet {nom: "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 et ensuite il donne cet objet au constructeur, alors le constructeur peut faire ce qu'il veut, parce que ce à l'intérieur de ce constructeur est l'objet qui vient d'être créé et puis il vous donne cet objet bien sûr si vous n'avez pas utilisé l'instruction de retour dans votre fonction ou si vous avez mis 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 __proto__attribut, il monte et monte jusqu'à ce qu'il arrive au point où la prochaine __proto__ est nul. Le point est le seul objet en JavaScript que son __proto__ l'attribut est nul Object.prototype objet:

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

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

The prototype chain

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 ira voir la fonction de .prototype et il est également possible que cet objet ait son propre prototype interne. etc.


162
2018-02-13 19:32



prototype vous permet de faire des classes. si vous n'utilisez pas prototype alors ça 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 ils ont tous le test fonction.

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.


66
2017-11-07 09:48



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 *[[protytype]]* and <code>prototype</code> property of function objects

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.


59
2018-05-26 20:40



Les sept Koans du prototype

Alors que Ciro San descendait Mount Fire Fox après une profonde méditation, son esprit était clair et paisible.

Cependant, sa main était agitée et, à elle seule, saisit un pinceau et nota les notes suivantes.


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

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

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

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

    Firefox le rend accessible à travers le __proto__ propriété en tant qu'extension. ES6 mentionne maintenant certaines exigences facultatives 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 est ne pas utilisé pour la recherche directement, seulement indirectement car il détermine __proto__ à la création d'objet avec new.

L'ordre de recherche est:

  • obj propriétés ajoutées avec obj.p = ... ou Object.defineProperty(obj, ...)
  • propriétés de obj.__proto__
  • propriétés de obj.__proto__.__proto__, etc
  • si quelques __proto__ est null, revenir undefined.

C'est ce que l'on appelle chaîne de prototypes.

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


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

  • new:

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

    puis new a mis:

    f.__proto__ === F.prototype
    

    Ce est ou .prototype s'habitue

  • 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 seulement créées 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

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

  • f n'a pas .constructor
  • f.__proto__ === F.prototype a .constructor === Falors 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 d'héritage classique peut être obtenue en manipulant des chaînes de prototypes.

ES6 ajoute le class et extends mots-clés, qui sont simplement la syntaxe du sucre pour la folie de manipulation de prototype précédemment 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

57
2018-06-18 19:48



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

object [[Prototype]] -> anotherObject

En javascript traditionnel, l'objet lié est le prototype propriété 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 La déclaration ne montre pas la cible du lien (Object.prototype) lui-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 un prototype propriété.
  • Objets créés avec new sont liés à la prototype propriété de leur constructeur.
  • Si une fonction n'est jamais utilisée en tant que constructeur, son prototype la propriété sera inutilisée.
  • Si vous n'avez pas besoin de constructeur, utilisez Object.create au lieu de new.

33
2018-02-21 12:41



Javascript n'a pas d'héritage au sens habituel, mais il a la chaîne du prototype.

chaîne de prototypes

Si un membre d'un objet ne peut pas être trouvé dans l'objet, il le cherche dans la chaîne prototype. La chaîne se compose d'autres objets. Le prototype d'une instance donnée peut être consulté avec le __proto__ variable. Chaque objet en a un, car il n'y a pas de différence entre les classes et les instances en javascript.

L'avantage d'ajouter une fonction / variable au prototype est qu'il ne doit être dans la mémoire qu'une seule fois, pas pour chaque instance.

C'est également utile pour l'héritage, car la chaîne du prototype peut être constituée de nombreux autres objets.


23
2017-11-04 14:08