Maison  >  Article  >  interface Web  >  Comprendre les modèles courants et les chaînes de prototypes

Comprendre les modèles courants et les chaînes de prototypes

PHP中文网
PHP中文网original
2017-06-20 09:37:301755parcourir

Contenu :

  • Plusieurs modes de création d'objets et le processus de création

  • Compréhension du prototype de chaîne de prototypes, et prototype et Plusieurs implémentations de la relation __proto__([[Prototype]])

  • héritage


1. Modèles communs et chaîne de prototypes Comprendre

a. Processus de création d'un constructeur

function Test() {// 
}

  • Lors de la création d'une fonction, un attribut de prototype sera créé pour Test par défaut, Test.prototype Contient un pointeur pointant vers Object.prototype

  • le prototype aura un constructeur par défaut, et d'autres méthodes dans Test.prototype.constructor = Test

  • prototype Hérité de Objet


Exemple
// 调用构造函数创建实例
var instance = new Test()

L'instance ici contient un pointeur vers le constructeur Le prototype de la fonction, (le pointeur ici s'appelle __proto__ en chrome, qui est également égal à [[Prototype]])


Exemple

b.
D'après ce qui précède, nous pouvons savoir que les propriétés du prototype créées par défaut n'ont qu'un constructeur et des propriétés héritées de l'objet. Le mode prototype consiste à ajouter des propriétés et des méthodes au prototype

Test.prototype.getName = ()=> {
    alert('name')
}

À ce stade, l'instance d'instance est Nous avons la méthode getName, car le pointeur d'instance pointe vers Test.prototype

instance.__proto__ === Test.prototype

comme indiqué dans la figure ci-dessous


897RVF ]E5@IX$) `IVJ3BOSY.png

Ici, nous pouvons savoir que l'instance d'instance et le constructeur sont liés via le prototype prototype.

c. Mode combinaison
Nous utilisons le plus ce mode. C'est en fait une autre façon d'écrire le mode prototype, avec juste une petite différence

function Test() {}

Test.prototype = {
    getName() {
        alert('name')
    }
}

Nous l'utilisons souvent directement. En réécrivant la méthode prototype, nous savons d'après ce qui précède que le prototype aura son propre attribut constructeur pointant vers le constructeur lui-même par défaut, alors que se passe-t-il après la réécriture ?

Test.prototype.constructor === Object 
// 而并不等于Test了// 因为重写以后相当于利用字面量方式创建一个实例对象,这个实例的构造函数是指向Object本身的

Bien sûr, nous pouvons également attribuer le constructeur manuellement

Test.prototype = {
    constructor: Test,
    getName() {
        alert('name')
    }
}

Ensuite, il y aura à nouveau des questionsconstructorA quoi ça sert de le faire ? Je pense que le sens du mot constructeur est simplement d'identifier le constructeur auquel appartient le prototype.

Lorsqu'un certain attribut doit être obtenu, il sera d'abord recherché à partir de l'instance. Sinon, il sera recherché en fonction du prototype pointé par le pointeur, puis vers le haut jusqu'au pointeur de l'instance <.> pointe vers null et la recherche s'arrêtera. Par exemple : __proto__

// 1 读取nameinstance.name 

// 2 instance.__proto__ === Test.prototypeTest.prototype.name

// 3 Test.prototype.__proto__ === Object.prototypeObject.prototype.name

// 4Object.prototype.__proto__ === null
Lorsque cet attribut sera trouvé, il sera renvoyé directement sans continuer la recherche Même si la valeur de l'attribut est nulle, si on le souhaite. pour continuer la recherche, nous pouvons utiliser l'opérateur

. delete

À partir de là, nous pouvons naturellement penser que

est un constructeur, et leurs pointeurs de prototype pointent vers Array, Date, Function, String Ils sont comme les Object.prototype que j'ai définis ici, mais ils sont natifs. Test

d. Plusieurs méthodes utiles

  • Faire pointer le prototype par le pointeur d'une instance Object.getPrototypeOf()

    Object.getPrototypeOf(instance) === Test.prototype
  • Déterminer si un attribut existe dans l'instance ou dans le prototype, comme indiqué dans la figure : hasOwnProperty


    NY~N} CNR`}8W %4QA$M8LFE4.png
  • opérateur, que l'attribut soit énumérable ou non in

    &#39;name&#39; in instance  // true
    &#39;getName&#39; in instance // true
    que l'attribut soit ou non Les deux renvoient vrai dans l'instance et dans le prototype, donc lorsque nous devons déterminer si un attribut existe dans l'instance ou dans le prototype, il existe deux méthodes

    // 一种就是使用hasOwnProperty判断在实例中
    // 另一种判断在原型中
    instance.hasOwnProperty(&#39;getName&#39;) === false && &#39;getName&#39; in instance === true
  • opération Le symbole est le même, mais seules les propriétés énumérables seront répertoriées. Le bug dans la version ie8 est que peu importe si la propriété est énumérable ou non, for ... in


    D. (%S__GN8404{H9X6PW$DVK.png


    name是在实例中定义的,getName是在原型中定义的

  • Object.keys()则不一样,它返回一个对象上所有可枚举的属性,仅仅是该实例中的

    Object.keys(instance)// ["name"]
  • e.总结
    以上讨论了构造函数,原型和实例的关系:

    • 每个构造函数都有原型对象

    • 每个原型对象都有一个constructor指针指向构造函数

    • 每个实例都有一个__proto__指针指向原型

    2.继承

    其实是一个道理,这里我们不难想到,将Child.prototype指向parent实例,就是利用原型实现的继承,而为了每个实例都拥有各自的colors和name,也就是基础属性,在Child的构造函数中call调用了Parent的构造函数,相当于每次实例化的时候都初始化一遍colors和name,而不是所有实例共享原型链中的colors和name。

    继承的实质是利用构造函数的原型 = 某个构造函数的实例,以此来形成原型链。例如

    // 定义父类function Parent() {}Parent.prototype.getName = ()=> {
        console.log(&#39;parent&#39;)
    }// 实例化父类let parent = new Parent()// 定义子类function Child() {}
    Child.prototype = parent 
    // 实例化子类let child = new Child()
    
    child.getName() // parent// 此时
    child.constructor === parent.constructor === Parent

    a.最经典的继承模式

    function Parent(name) {this.name = namethis.colors = [&#39;red&#39;]
    }
    Parent.prototype.getName = function() {console.log(this.name)
    }// 实例化父类let parent = new Parent()function Child(age, name) {
        Parent.call(this, name)this.age = age
    }
    Child.prototype = parent 
    // 实例化子类let child = new Child(1, &#39;aaa&#39;)
    child.getName() // parent

    这里会让我想到ES6中的class继承

    class Parent {
        constructor(name) {this.name = namethis.colors = [&#39;red&#39;]
        }
        getName() {
            console.log(this.name)
        }
    }class Child extends Parent {
        constructor(age, name) {super(name)
        }
    }
    
    let child = new Child(1, &#39;aaa&#39;)
    child.getName() // parent

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:Solution vide dans la liste déroulante AngularjsArticle suivant:Solution vide dans la liste déroulante Angularjs

Articles Liés

Voir plus