Aperçu
Tous les objets en JavaScript ont leur propre chaîne d'héritage. C'est-à-dire que chaque objet hérite d'un autre objet, qui est appelé un objet "prototype". À l'exception de NULL, il n'a pas son propre objet prototype.
L'importance d'un objet prototype est que si l'objet A est un prototype de l'objet B, l'objet B peut obtenir toutes les propriétés et méthodes de l'objet A. La méthode objet.getprototypof est utilisée pour obtenir l'objet prototype de l'objet actuel.
var p = object.getPrototypeOf (obj);
Dans le code ci-dessus, l'objet P est l'objet prototype de l'objet obj.
La méthode objet.Create est utilisée pour générer un nouvel objet et hériter de l'objet spécifié.
var obj = object.create (p);
Dans le code ci-dessus, le prototype de l'objet OBJ nouvellement généré est l'objet p.
L'attribut __proto__ non standard (deux soulignements devant et derrière) peut réécrire l'objet prototype d'un certain objet. Cependant, vous devez essayer d'utiliser cette propriété le moins possible, mais utiliser object.getPrototypeOf () et object.setPrototypeOf () pour lire et écrire des objets prototypes.
var obj = {}; var p = {}; obj .__ proto__ = p; objet.getprototypeof (obj) === p // trueLe code ci-dessus définit l'objet P comme le prototype de l'objet OBJ via l'attribut __proto__.
Voici un exemple pratique.
var a = {x: 1}; var b = {__proto__: a}; bx // 1Dans le code ci-dessus, l'objet B définit son objet prototype en tant qu'objet via l'attribut __proto__, afin que l'objet B puisse obtenir toutes les propriétés et méthodes de l'objet a. L'objet B lui-même n'a pas d'attribut x, mais le moteur JavaScript trouve son objet prototype A via l'attribut __proto__, puis lit l'attribut x de a.
La nouvelle commande crée un nouvel objet d'instance via un constructeur. Il lie essentiellement le prototype de l'objet d'instance dans la propriété Prototype du constructeur, puis en exécutant le constructeur sur l'objet d'instance.
var o = new foo (); // équivaut à var o = new object (); o .__ proto__ = foo.prototype; foo.call (o);
L'attribut __proto__ de l'objet prototype peut également pointer vers d'autres objets, formant ainsi un niveau de "chaîne prototype" par niveau.
var a = {x: 1}; var b = {__proto__: a}; var c = {__proto__: b}; cx // 1Il convient de noter que la recherche d'un certain attribut dans la chaîne prototype a un impact sur les performances. Plus le niveau de l'objet prototype que vous recherchez est élevé, plus l'impact sur les performances est élevé. Si vous recherchez une propriété inexistante, elle traversera toute la chaîne prototype.
Cette action pointant
Peu importe où cela est défini, lorsqu'il est utilisé, il pointe toujours vers l'objet actuel, pas l'objet Prototype.
var o = {a: 2, m: function (b) {return this.a + 1; }}; var p = object.create (o); pa = 12; pm () // 13Dans le code ci-dessus, la méthode m de l'objet P provient de son objet prototype o. À l'heure actuelle, cet objet à l'intérieur de la méthode M ne pointe pas vers O, mais à p.
Héritage des constructeurs
Cette section présente comment faire un constructeur hériter d'un autre constructeur.
Supposons qu'il existe un constructeur de forme.
Fonction Shape () {this.x = 0; this.y = 0;} forme.prototype.move = fonction (x, y) {this.x + = x; this.y + = y; console.info ('forme déplacé.');}; Le constructeur rectangulaire hérite de la forme. fonction rectangle () {shape.call (this); // appelle le constructeur de classe parent} // une autre façon d'écrire la fonction rectangle () {this.base = forme; this.base ();} // sous-classe hérite de la méthode de la classe parent rectangle.prototype = object.create (shape.prototype); rect.prototype.constructor = rectangle; var rect = nouveau recangle (); rect instanceof rectangle // truerect instance forme // truerect.move (1, 1) // 'forme de forme.Le code ci-dessus montre que l'héritage du constructeur est divisé en deux parties, l'une est que la sous-classe appelle la méthode du constructeur de la classe parent, et l'autre est que le prototype de la sous-classe pointe vers le prototype de la classe parent.
Dans le code ci-dessus, la sous-classe hérite de la classe parent dans son ensemble. Parfois, seul l'héritage d'une seule méthode est nécessaire et la méthode d'écriture suivante peut être utilisée.
Classb.prototype.print = function () {classa.prototype.print.call (this); // du code}Dans le code ci-dessus, la méthode d'impression de la sous-classe B appelle d'abord la méthode d'impression de la classe A parent A, puis déploie son propre code. Cela équivaut à hériter de la méthode d'impression de la classe des parents A.
__Proto__ Attribut
L'attribut __proto__ pointe vers l'objet prototype de l'objet actuel, c'est-à-dire l'attribut prototype du constructeur.
var obj = new object (); obj .__ proto__ === object.prototype // trueobj .__ proto__ === obj.constructor.prototype // true
Le code ci-dessus crée d'abord un nouvel objet obj, son attribut __proto__, pointant vers l'attribut prototype du constructeur (objet ou obj.constructor). Par conséquent, après avoir comparé les deux, revenez vrai.
Par conséquent, il existe trois façons d'obtenir l'objet prototype de l'objet d'instance obj.
Parmi les trois méthodes ci-dessus, les deux premiers ne sont pas très fiables. Le dernier ES6 standard stipule que seul le navigateur doit déployer l'attribut __proto__, et d'autres environnements peuvent ne pas être déployés. Cependant, obj.constructor.prototype peut échouer lors de la modification manuelle de l'objet prototype.
var p = function () {}; var p = new p (); var c = function () {}; c.prototype = p; var c = new C (); c.constructor.prototype === p // falseDans le code ci-dessus, l'objet prototype du constructeur C est changé en p, et le résultat est que C.Contructor.Protype est déformé. Par conséquent, lors de la modification de l'objet Prototype, l'attribut de constructeur doit être défini en même temps.
C.prototype = p; c.prototype.constructor = c; c.constructor.prototype === p // true
Par conséquent, il est recommandé d'utiliser le troisième objet.GetPrototypeOf Méthode pour obtenir l'objet Prototype. L'utilisation de cette méthode est la suivante.
var o = new object (); object.getprototypeof (o) === object.prototype // true
Vous pouvez utiliser la méthode object.getPrototypeOf pour vérifier si le navigateur prend en charge l'attribut __proto__, qui n'est pas pris en charge par les anciens navigateurs.
Object.getprototypeof ({__proto__: null}) === nullLe code ci-dessus définit l'attribut __proto__ d'un objet à NULL, puis utilise l'objet.getPrototypeOf Méthode pour obtenir le prototype de cet objet pour déterminer s'il est égal à Null. Si l'environnement actuel prend en charge l'attribut __proto__, le résultat de comparaison des deux devrait être vrai.
Avec l'attribut __proto__, il est facile de configurer le prototype de l'objet d'instance. Supposons qu'il y ait trois objets: la machine, le véhicule et la voiture, où la machine est le prototype de véhicule et de véhicule est le prototype de voiture, qui peut être réglé avec seulement deux lignes de code.
véhicule .__ proto__ = machine; voiture .__ proto__ = véhicule;
Ce qui suit est un exemple. Les propriétés définies sur l'objet Prototype sont lues respectivement via l'attribut __proto__ et l'attribut Constructor.Prototype.
Array.prototype.p = 'abc'; var a = new Array (); a .__ proto __. P // abca.constructor.prototype.p // abc
De toute évidence, __proto__ semble un peu plus concis.
Lorsqu'un objet d'instance est généré via un constructeur, l'attribut __proto__ de l'objet d'instance pointe automatiquement vers l'objet Prototype du constructeur.
var f = function () {}; var a = {}; f.prototype = a; var o = new f (); o .__ proto__ === a // trueHéritage des attributs
Il existe deux types d'attributs. L'un est l'attribut natif de l'objet lui-même, et l'autre est l'attribut hérité hérité du prototype.
Propriétés natives d'un objet
Toutes les propriétés de l'objet lui-même peuvent être obtenues à l'aide de la méthode objet.getownpropertyNames.
Object.getownpropertyNames (date) // ["analyse", "arguments", "utc", "appelant", "nom", "prototype", "maintenant", "longueur"]
Parmi les propriétés de l'objet lui-même, certains sont énumérables (énumérés), tandis que d'autres ne sont pas énumérés. Obtenez uniquement les propriétés qui peuvent être énumérées, utilisez la méthode Object.Keys.
Object.keys (date) // [] HasownProperty ()
La méthode HasownProperty renvoie une valeur booléenne pour déterminer si une certaine propriété est définie sur l'objet lui-même ou sur la chaîne prototype.
Date.hasownproperty ('longueur') // trueate.hasownproperty ('toString') // falseLa méthode HasownProperty est la seule méthode de JavaScript qui ne traverse pas la chaîne prototype lors du traitement des propriétés d'objets.
Propriétés de l'héritage d'un objet
Les objets créés avec la méthode Object.Create hériteront des propriétés de tous les objets prototypes.
var proto = {p1: 123}; var o = object.create (proto); o.p1 // 123o.hasownproperty ("p1") // falseObtenez tous les attributs
Pour déterminer si un objet a une certaine propriété (qu'il soit sien ou hérité), utilisez l'opérateur in.
"longueur" dans la date // true "tostring" dans la date // true
Obtenez toutes les propriétés énumérables d'un objet (qu'elle soit propre ou héritée), et vous pouvez utiliser une boucle for-in.
var o1 = {p1: 123}; var o2 = object.create (o1, {p2: {value: "ABC", énuable: true}}); pour (p dans o2) {console.info (p);} // p2 // p1Afin d'obtenir les propres propriétés de l'objet dans la boucle pour ... en boucle, vous pouvez utiliser la méthode HasownProperty pour juger.
for (var name in object) {if (object.hasownproperty (name)) {/ * code de boucle * /}}Pour obtenir toutes les propriétés de l'objet (qu'il soit propre ou hérité, et qu'il soit énumérable), vous pouvez utiliser la fonction suivante.
fonction héritéePropertyNames (obj) {var props = {}; while (obj) {object.getownpropertyNames (obj) .ForEach (function (p) {props [p] = true;}); obj = object.getPrototypeOf (obj); } return object.getownpropertyNames (accessoires);}L'utilisation est la suivante:
INHÉRIRÉPROPERTYNAMES (DATE) // ["CALLER", "Constructeur", "TOSTRING", "UTC", "Call", "Parse", "Prototype", "__defineSetter__", "__LookupSetter__", "Longueur", "Arguments", "Bind" "PropertyIsenumerable", "ValueOf", "Appliquer", "__deFinegetter__", "Name", "Now", "HasownProperty"]
Copie de l'objet
Si vous souhaitez copier un objet, vous devez faire les deux choses suivantes.
Assurez-vous que l'objet copié a le même objet prototype que l'objet d'origine.
Assurez-vous que l'objet copié a les mêmes propriétés que l'objet d'origine.
Ce qui suit est la fonction de copie de l'objet écrit en fonction des deux points ci-dessus.
fonction copyObject (orig) {var copy = object.create (object.getPrototypeOf (orig)); CopyOwnPropertiesFrom (copie, orig); return copy;} function copyownPropertiesFrom (cible, source) {object .getownpropertyNames (source) .ForEach (function (propKey) {var desc = object.getownpropertyDescriptor (source, propKey); object.defineproperty (cible, propy, desc);}); Retour cible;}Héritage multiple
JavaScript ne fournit pas plusieurs fonctions d'héritage, c'est-à-dire qu'elle ne permet pas à un objet d'hériter plusieurs objets en même temps. Cependant, cette fonction peut être obtenue grâce à des solutions de contournement.
fonction m1 (prop) {this.hello = prop;} fonction m2 (prop) {this.world = prop;} fonction s (p1, p2) {this.base1 = m1; this.base1 (p1); this.base2 = m2; this.base2 (p2);} s.prototype = new M1 (); var s = new S (111, 222); s.hello // 111s.world // 222Dans le code ci-dessus, la sous-classe S hérite à la fois les classes parentales M1 et M2. Bien sûr, du point de vue de la chaîne d'héritage, S n'a qu'une seule classe parent M1, mais comme en cas de S, les constructeurs de M1 et M2 sont exécutés en même temps, il hérite des méthodes de ces deux classes en même temps.