Maison  >  Article  >  interface Web  >  Résumé des éléments à prendre en compte dans la chaîne de prototypes JavaScript

Résumé des éléments à prendre en compte dans la chaîne de prototypes JavaScript

不言
不言avant
2018-10-20 15:59:551652parcourir

Ce que cet article vous apporte est un résumé de ce à quoi vous devez prêter attention dans la chaîne de prototypes JavaScript. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Avant-propos : J'ai récemment lu Javascript Advanced Programming. Pour moi, la version chinoise du livre a des traductions insatisfaisantes à de nombreux endroits, j'essaie donc de l'interpréter en utilisant ce que je comprends. S'il y a des erreurs ou des omissions, nous vous serions très reconnaissants de les signaler. La plupart du contenu de cet article est tiré de "JavaScript Advanced Programming, Third Edition"

1 N'oubliez pas le prototype par défaut

En fait, le prototype. chaîne montrée dans l'exemple précédent. Un maillon est manquant.

Nous savons tous que tous les types de référence héritent de Object par défaut, et cet héritage est également implémenté via la chaîne de prototypes.

Le prototype par défaut de toutes les fonctions est une instance d'Object. Parce que l’objet prototype d’une fonction est aussi un objet ! L'objet est bien sûr une instance d'Object!

Par conséquent, le prototype de la fonction contiendra un pointeur interne (__proto__), pointant vers Object.prototype.

C'est aussi la raison fondamentale pour laquelle tous les types personnalisés héritent des méthodes par défaut telles que toString() et valueOf().

Ainsi, la chaîne de prototypes du prototype présenté dans l'exemple précédent devrait également inclure un autre niveau d'héritage.

Le code suivant montre cette chaîne prototype complète.

//完整原型链的伪代码
function Object() {
}
Object.prototype = {
    constructor: f Object(),
    hasOwnProperty: f hasOwnProperty(),
    isPrototypeOf: f isPrototypeOf(),
    propertyIsEnumerable: f propertyIsEnumerable(),
    toLocaleString: f toLocaleString(),
    toString: f toString(),
    valueOf: f valueOf()
}
//SuperType 父类型
function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperProperty = function() {
    console.log(this.property);
    return this.property;
}
/*
SuperType.prototype = {
    constructor: f SuperType(),
    getSuperProperty: function() {
    console.log(this.property);
    return this.property;
    }, 
    __proto__ : {
        constructor: f Object(),
        hasOwnProperty: f hasOwnProperty(),
        isPrototypeOf: f isPrototypeOf(),
        propertyIsEnumerable: f propertyIsEnumerable(),
        toLocaleString: f toLocaleString(),
        toString: f toString(),
        valueOf: f valueOf()
    }
}
*/
//SubType 子类型
function SubType() {
    this.subproperty = false;
}
//子类型 继承 父类型
SubType.prototype = new SuperType();
//实际上子类型的原型是这样的。
/*SubType.prototype = {
    property: true,
    __proto__:  {
        constructor : SuperType,
        getSuperProperty:function() {
            console.log(this.property);
            return this.property;
        }
    }
}
*/
SubType.prototype.getSubProperty = function(){
    console.log(this.subproperty);
    return this.subproperty;
}
//那么现在子类型的原型对象是这样的
/*SubType.prototype = {
    property: true,
    getSubProperty: function()  {
    console.log(this.subproperty);
    return this.subproperty;
    },
    __proto__:  {
        constructor : SuperType,
        getSuperProperty:function() {
            console.log(this.property);
            return this.property;
        }
    }
}
*/

var subInstanceObject = new SubType();
console.log(subInstanceObject.getSuperProperty()); // true

En un mot, SubType (sous-type) hérite de SuperType (type parent),

et SuperType (type parent) hérite d'Object (ancêtre).

Lorsque subInstanceObject.toString() est appelé, la méthode enregistrée dans Object.prototype est en fait appelée.

2. Déterminer la relation entre les objets prototype et instance

La relation entre le prototype et l'instance peut être déterminée de deux manières.

La première méthode consiste à utiliser l'opérateur instanceof. Tant que la chaîne de prototypes dans l'objet instance détecté contient un constructeur qui est apparu, le résultat retournera vrai.
Parce que cela montre qu'ils sont tous impliqués dans la création d'objets instances.

console.log(subInstanceObject instanceof Object); // true
console.log(subInstanceObject instanceof SuperType); // true
console.log(subInstanceObject instanceof SubType); // true

En raison de la chaîne de prototypes, nous pouvons dire que subIntanceObject est une instance de n'importe quel type parmi Object, SuperType ou SubType.

La deuxième façon consiste à utiliser la méthode isPrototypeOf(). De même, tant qu'il s'agit d'un prototype qui apparaît dans la chaîne de prototypes, on peut dire qu'il s'agit du prototype de l'objet instance dérivé de la chaîne de prototypes.

console.log(Object.prototype.isPrototypeOf(subInstanceObject)); //true
console.log(SuperType.prototype.isPrototypeOf(subIntanceObject)); // true
console.log(SubType.prototype.isPrototypeOf(subIntanceObject)); //true

3. Définissez soigneusement les méthodes

Les sous-types doivent parfois remplacer une méthode du type parent, ou ajouter une méthode qui n'existe pas dans le type parent. . méthode.

Mais quoi qu'il en soit, le code qui ajoute des méthodes au prototype doit être placé après l'instruction qui remplace le prototype.

function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function() {
    return this.property;
}

function SubType() {
    this.subproperty = false;
}

//继承了SuperType
SubType.prototype = new SuperType();

//给原型添加方法的代码一定要放在替换原型的语句之后
//添加新方法
SubType.prototype.getSubValue = function() {
    return this.subproperty;
}

//重写 超类型中 的 方法
SubType.prototype.getSuperValue = function() {
    return false;
}

var instance = new SubType();
console.log(instance.getSuperValue())

Dans le code ci-dessus, la première méthode getSubValue() est ajoutée à SubType.
La deuxième méthode getSuperValue() est une méthode qui existe déjà dans le prototype.
Le remplacement de cette méthode amènera le prototype de la sous-classe à trouver sa propre méthode getSuperValue().
Lorsque getSuperValue() est appelée via l'objet instance SuperType, la méthode d'origine continuera à être appelée.

Encore une fois, vous devez définir deux méthodes après avoir remplacé le prototype par un objet instance de SuperType.

Une autre chose à noter est que lors de l'implémentation de l'héritage via la chaîne de prototypes, les littéraux d'objet ne peuvent pas être utilisés pour créer des méthodes prototypes. Cela réécrira la chaîne de prototypes.

function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subproperty = false;
}

//继承SuperType
SubType.prototype = new SuperType();

/* 
现在的原型
SubType.prototype = {

    property: true,
    __proto__: {
        constructor: SuperType,
        getSuperValue: function() {
            return this.property;
        }
    }
}
*/

//使用对象字面量语法会改写原型,导致上一行代码无效
// SubType.prototype = new Object();
SubType.prototype = {

    getSubValue: function() {
        return this.subproperty;
    },

    someOtherMethod: function () {
        return false;
    }

    /*,
    __proto__ : {
        constructor: fn Object(),
        .......
    }
    */

}

var instance =  new SubType();
console.log(instance.getSuperValue()); // error: instance.getSuperValue is not a function

Le code ci-dessus montre le problème causé par la simple attribution de l'objet instance de SuperType au prototype, puis par le remplacement du prototype par un objet littéral.

Étant donné que le prototype de SubType enregistre en fait une instance d'Object au lieu d'une instance d'objet de SuperType, cette chaîne est rompue.

4. Problèmes avec la chaîne de prototypes

Bien que la chaîne de prototypes soit très puissante et puisse être utilisée pour implémenter l'héritage, elle présente toujours des défauts. dans le monde.

Le principal problème vient des prototypes contenant des valeurs de type référence.

Les propriétés du prototype contenant des valeurs de type référence sont partagées par tous les objets d'instance.

Et c'est exactement pourquoi le modèle de prototype et le modèle de constructeur sont utilisés en combinaison.
Définissez les propriétés dans le modèle de constructeur et définissez les méthodes partagées dans le modèle de prototype.

Lors de l'implémentation de l'héritage prototypique via un prototype, le prototype devient en fait un objet instance d'un autre type.

Les propriétés de l'objet d'instance d'origine sont devenues les propriétés actuelles du prototype.

function SuperType() {
    this.colors = ['red', 'green', 'blue'];
}

function SubType() {
}

// 子类型继承父类型
SubType.prototype = new SuperType();

/*
SubType.prototype = {
    colors: ['red', 'green', 'blue'],
    __proto__: {
        constructor: fn SuperType(),
        .....
    }
}
*/

var instance1 = new SubType();

instance1.colors.push('black');

console.log(instance1.colors); // ['red', 'green', 'blue', 'black']

var instance2 = new SubType();

console.log(instance2.colors); // ['red', 'green', 'blue', 'black']

Le deuxième problème avec la chaîne de prototypes est qu'il n'y a aucun moyen de transmettre des paramètres au constructeur du type parent sans affecter tous les objets d'instance.

En raison des deux problèmes ci-dessus, la chaîne prototype est rarement utilisée seule lors d'événements.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer