Maison  >  Article  >  interface Web  >  Comment JavaScript implémente-t-il l’héritage ? Six méthodes d'héritage courantes en js

Comment JavaScript implémente-t-il l’héritage ? Six méthodes d'héritage courantes en js

青灯夜游
青灯夜游original
2018-10-17 14:28:228574parcourir

Comment implémenter l'héritage en JavaScript ? Cet article vous présentera six méthodes d'héritage courantes en js. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

Avant-propos

Un aspect très important de la programmation orientée objet est l'héritage d'objet. En héritant de l'objet B, l'objet A peut posséder directement toutes les propriétés et méthodes de l'objet B. Ceci est très utile pour la réutilisation du code.

La plupart des langages de programmation orientés objet implémentent l'héritage d'objets via des "classes". Traditionnellement, l'héritage du langage JavaScript n'est pas implémenté via des classes (ES6 a introduit la syntaxe de classe), mais via des « prototypes ». Alors, quelles sont les méthodes d’héritage courantes en JS ?

Si vous avez besoin du code source de cet article, veuillez cliquer sur Six méthodes d'héritage courantes

Si vous pensez que l'article vous est utile, n'hésitez pas libre de le publier sur mon blog GitHub Aimez et suivez, merci beaucoup !

Méthode 1. Héritage de la chaîne de prototypes

La clé de cette méthode est : Le prototype du sous-type est un objet instance du type parent.

       //父类型
       function Person(name, age) {
           this.name = name,
           this.age = age,
           this.play = [1, 2, 3]
           this.setName = function () { }
       }
       Person.prototype.setAge = function () { }
       //子类型
       function Student(price) {
           this.price = price
           this.setScore = function () { }
       }
       Student.prototype = new Person() // 子类型的原型为父类型的一个实例对象
       var s1 = new Student(15000)
       var s2 = new Student(14000)
       console.log(s1,s2)

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

Mais l'essence de cette méthode est de pointer le prototype de la sous-classe vers l'instance du parent class , afin que l'instance de la sous-classe puisse accéder à Student.prototype, qui est l'instance de Person, via __proto__, afin qu'elle puisse accéder à la méthode privée de la classe parent, puis pointer vers le prototype de la classe parent via __proto__ Obtenez la méthode sur le prototype de la classe parent. Ainsi les méthodes et propriétés privées et publiques de la classe parent sont traitées comme les propriétés publiques de la sous-classe

La classe enfant hérite des propriétés et méthodes de la classe parent et traite les propriétés privées et les méthodes publiques de la classe parent en tant que Nos propres attributs et méthodes publics , nous savons tous que lorsque nous opérons sur des types de données de base, nous opérons sur des valeurs, et lorsque nous opérons sur des types de données de référence, nous opérons sur des adresses s'il y a des attributs de type référence dans. les attributs privés de la classe parent, alors il sera utilisé comme attribut public lorsqu'il est hérité par une sous-classe, donc lorsque la sous-classe 1 exploite cet attribut, cela affectera la sous-classe 2.

       s1.play.push(4)
       console.log(s1.play, s2.play)
       console.log(s1.__proto__ === s2.__proto__)//true
       console.log(s1.__proto__.__proto__ === s2.__proto__.__proto__)//true

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

L'attribut play dans s1 change. En même temps, l'attribut play dans s2 changera également.

Une autre chose à noter est que Lorsque nous devons ajouter une nouvelle méthode à une sous-classe ou remplacer une méthode de la classe parent, n'oubliez pas de la mettre après l'instruction qui remplace le prototype

       function Person(name, age) {
           this.name = name,
           this.age = age
       }
       Person.prototype.setAge = function () {
           console.log("111")
       }
       function Student(price) {
           this.price = price
           this.setScore = function () { }
       }
       // Student.prototype.sayHello = function () { }//在这里写子类的原型方法和属性是无效的,
      //因为会改变原型的指向,所以应该放到重新指定之后
       Student.prototype = new Person()
       Student.prototype.sayHello = function () { }
       var s1 = new Student(15000)
       console.log(s1)

Fonctionnalités :

  • La classe parent a ajouté des méthodes/attributs de prototype, accessibles aux sous-classes

  • Simple et facile à mettre en œuvre

Inconvénients :

  • Impossible de mettre en œuvre l'héritage multiple

  • Toutes les propriétés de l'objet prototype sont partagées par toutes les instances

  • Lors de la création d'une instance de sous-classe, les paramètres ne peuvent pas être transmis au constructeur de la classe parent

  • Si vous souhaitez ajouter des attributs et des méthodes à une sous-classe, ils doivent être exécutés après Student.prototype = new Person() et ne peuvent pas être placés dans le constructeur

Méthode 2 : emprunter l'héritage du constructeur

La clé de cette approche est : Utiliser un appel universel() dans le constructeur de sous-type pour appeler le constructeur de type parent

<script>
  function Person(name, age) {
    this.name = name,
    this.age = age,
    this.setName = function () {}
  }
  Person.prototype.setAge = function () {}
  function Student(name, age, price) {
    Person.call(this, name, age)  // 相当于: this.Person(name, age)
    /*this.name = name
    this.age = age*/
    this.price = price
  }
  var s1 = new Student(&#39;Tom&#39;, 20, 15000)</script>

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

Cette méthode n'implémente que l'héritage partiel. Si le prototype de la classe parent possède également des méthodes et des attributs, la sous-classe ne peut pas obtenir ces méthodes et attributs.

console.log(s1.setAge())//Uncaught TypeError: s1.setAge is not a function

Fonctionnalités :

  • Résoudre le problème des instances de sous-classe partageant les attributs de référence de classe parent dans l'héritage de chaîne de prototypes

  • Lors de la création d'une instance de sous-classe, vous pouvez transmettre des paramètres à la classe parent

  • Vous pouvez implémenter l'héritage multiple (appeler plusieurs objets de classe parent)

Inconvénients :

  • Les instances ne sont pas des instances de la classe parent, mais uniquement des instances de la sous-classe

  • Vous ne pouvez hériter que des propriétés et méthodes d'instance de la classe parent, mais pas des propriétés et méthodes du prototype.

  • La réutilisation des fonctions ne peut pas être réalisée. Chaque sous-classe a une copie du parent. fonction d'instance de classe, qui affecte les performances

Méthode 3 : Chaîne de prototypes + héritage combiné des constructeurs empruntés

La clé de cette méthode est : En appelant le parent constructeur de classe, hérite des propriétés de la classe parent et conserve les avantages du passage des paramètres, puis utilise l'instance de classe parent comme prototype de la sous-classe pour réaliser la réutilisation des fonctions.

        function Person(name, age) {
            this.name = name,
            this.age = age,
            this.setAge = function () { }
        }
        Person.prototype.setAge = function () {
            console.log("111")
        }
        function Student(name, age, price) {
            Person.call(this,name,age)
            this.price = price
            this.setScore = function () { }
        }
        Student.prototype = new Person()
        Student.prototype.constructor = Student//组合继承也是需要修复构造函数指向的
        Student.prototype.sayHello = function () { }
        var s1 = new Student('Tom', 20, 15000)
        var s2 = new Student('Jack', 22, 14000)
        console.log(s1)
        console.log(s1.constructor) //Student
        console.log(p1.constructor) //Person

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

这种方式融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。不过也存在缺点就是无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数的内部,子类型最终会包含父类型对象的全部实例属性,但我们不得不在调用子类构造函数时重写这些属性。

优点

  • 可以继承实例属性/方法,也可以继承原型属性/方法

  • 不存在引用属性共享问题

  • 可传参

  • 函数可复用

缺点

  • 调用了两次父类构造函数,生成了两份实例

方式四: 组合继承优化1

这种方式通过父类原型和子类原型指向同一对象,子类可以继承到父类的公有方法当做自己的公有方法,而且不会初始化两次实例方法/属性,避免的组合继承的缺点

       function Person(name, age) {
            this.name = name,
                this.age = age,
                this.setAge = function () { }
        }
        Person.prototype.setAge = function () {
            console.log("111")
        }
        function Student(name, age, price) {
            Person.call(this, name, age)
            this.price = price
            this.setScore = function () { }
        }
        Student.prototype = Person.prototype
        Student.prototype.sayHello = function () { }
        var s1 = new Student('Tom', 20, 15000)
        console.log(s1)

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

但这种方式没办法辨别是对象是子类还是父类实例化

console.log(s1 instanceof Student, s1 instanceof Person)//true true
console.log(s1.constructor)//Person

优点

  • 不会初始化两次实例方法/属性,避免的组合继承的缺点

缺点

  • 没办法辨别是实例是子类还是父类创造的,子类和父类的构造函数指向是同一个。

方式五: 组合继承优化2

借助原型可以基于已有的对象来创建对象,var B = Object.create(A)以A对象为原型,生成了B对象。B继承了A的所有属性和方法。

       function Person(name, age) {
            this.name = name,
            this.age = age
        }
        Person.prototype.setAge = function () {
            console.log("111")
        }
        function Student(name, age, price) {
            Person.call(this, name, age)
            this.price = price
            this.setScore = function () {}
        }
        Student.prototype = Object.create(Person.prototype)//核心代码
        Student.prototype.constructor = Student//核心代码
        var s1 = new Student('Tom', 20, 15000)
        console.log(s1 instanceof Student, s1 instanceof Person) // true true
        console.log(s1.constructor) //Student
        console.log(s1)

同样的,Student继承了所有的Person原型对象的属性和方法。目前来说,最完美的继承方法!

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

方式六:ES6中class 的继承

ES6中引入了class关键字,class可以通过extends关键字实现继承,还可以通过static关键字定义类的静态方法,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

需要注意的是,class关键字只是原型的语法糖,JavaScript继承仍然是基于原型实现的

       class Person {
            //调用类的构造方法
            constructor(name, age) {
                this.name = name
                this.age = age
            }
            //定义一般的方法
            showName() {
                console.log("调用父类的方法")
                console.log(this.name, this.age);
            }
        }
        let p1 = new  Person('kobe', 39)
        console.log(p1)
        //定义一个子类
        class Student extends Person {
            constructor(name, age, salary) {
                super(name, age)//通过super调用父类的构造方法
                this.salary = salary
            }
            showName() {//在子类自身定义方法
                console.log("调用子类的方法")
                console.log(this.name, this.age, this.salary);
            }
        }
        let s1 = new Student('wade', 38, 1000000000)
        console.log(s1)
        s1.showName()

Comment JavaScript implémente-t-il l’héritage ? Six méthodes dhéritage courantes en js

优点

  • 语法简单易懂,操作更方便

缺点

  • 并不是所有的浏览器都支持class关键字

总结:以上就是本篇文的全部内容,代码很简单,大家可以动手试试。希望能对大家的学习有所帮助,更多相关教程请访问JavaScript视频教程jQuery视频教程bootstrap教程

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