• JavaScript基于原型实现继承


    首先来了解几个常见的名称(以下解释依据本文实力代码场景)

    Object:对象(对象的值可以为任意类型,array,object,function......)

    prototype:原型对象

    constructor:构造函数

    __proto__:指向Person.prototype的原型对象

     

    一、函数的prototype属性

    JavaScript规定,每一个构造函数都有一个特别的属性prototype,该属性的值是一个对象,这个对象就是我们常说的“原型对象”。这个原型对象的所有属性和方法,都会被构造函数的实例对象继承。

    1.现,有如下函数Person

         function Person(name){
             this.name = name
         }

    2.Person函数的prototype属性(即,原型对象),如下

    根据打印出来的结果显示:

    2.1.Person.prototype的属性包含两项constructor(构造函数)和__proto__

    2.2.其中Person.prototype的构造函数constructor为Person函数本身,即

             console.log(Person.prototype.constructor === Person)  // true

     2.3.Person.prototype的__proto__属性指向对象的原型对象,即

          函数是Object的实例。

              Person.prototype.__proto__ == Object.prototype

     二、通过prototype和__proto__来实现继承

    通过将对象A的__proto__属性赋值为对象B

    即,A.__proto__ = B

    此时使用A.__proto__便可以访问B的属性和方法

    通过以上可以得出结论:

    JavaScript可以在两个对象之间创建一个关联,使得一个对象可以访问另一个对象的属性和方法,从而实现了继承。

     三、构造函数和实例对象

         function Person(name){
             this.name = name
         }
         var lily = new Person('Lily')

                  其中:lily.__proto__ = Person.prototype

    结论:

    1. 每个函数的原型对象(Person.prototype)都拥有constructor属性,指向该原型对象的构造函数(Person)
    2. 使用构造函数(Person)可以创建对象( new Person() ),创建的对象称为实例对象(lily)
    3. 实例对象通过将__proto__属性指向构造函数的原型对象(Person.prototype),实现了该原型对象的继承(lily.__proto__=Person.prototype)

    四、prototype和__proto__的关系

    1. 每个对象都有__proto__属性来标识自己所继承的原型对象,但只有函数才有prototype属性。
    2. 对于函数来说,每个函数都有一个prototype属性,该属性为该函数的原型对象。
    3. 通过将实例对象的__proto__属性赋值为其构造函数的原型对象prototype,JavaScript可以使用构造函数创建对象的方式来实现继承。

     五、通过原型链访问对象的方法和属性

    1.首先会优先在该对象上搜寻

    2.如果找不到,还会一次层层向上搜索该对象的原型对象、该对象的原型对象的原型对象等(套娃告警)

        lily.__proto__ = Person.prototype
        Person.prototype.__proto__ = Object.prototype
        Object.prototype.__proto__ = null

    3.JavaScript中的所有对象都是来自Object

    4.Object.prototype.__proto__ ===  null

    5.null没有原型,并作为这个原型链中的最后一个环节

    6.JavaScript会遍历访问对象的整个原型链

    7.如果最后依然找不到,此时会认为该对象的属性值为undefined

       8.示例解释,基于原型链的对象属性的访问过程,如下

     六、通过原型链访问属性的性能特点

    function Person(name){
       this.name = name  
    }

    var lily = new Person('Lily');
    lily.__proto__ = Person.prototype
    Person.prototype.__proto__ = Object.prototype
    Object.prototype.__proto__ = null

    当试图访问不存在的属性时,会遍历整个原型链,在原型链上查找属性比较耗时,对性能有副作用,这在性能要求苛刻的情况下很重要。

    七、JavaScript中实现继承的方式

    1.经典继承(盗用构造函数)

    可以实现实例属性私有,但要求类型只能通过构造函数来定义

    function Person(name){
      // 私有属性,不共享
      this.name = name    
    }

    2.组合继承(JavaScript中常见的继承模式)

    通过将需要复用、共享的方法定义在父类原型上,结合构造函数和原型式继承的优点

    function Person(name){
      // 私有属性,不共享
      this.name = name    
    }
    
    Parent.prototype.speak = function(){
      console.log("hello")  
    }

    3.原型式继承

    引用类型的属性被所有实例共享,无法做到实例私有

    4.寄生式继承

  • 相关阅读:
    03人脉搜索:学会这一招,就能轻松找到90%的人的联系方式
    02 资源搜索-全面、快速查找全网你想要的任何信息、情报
    01信息搜索:全面、快速查找全网你想要的任何信息、情报.
    ansible笔记(12):handlers的用法
    ansible笔记(11):初识ansible playbook(二)
    ansible笔记(10):初识ansible playbook
    ansible笔记(9):常用模块之包管理模块
    ansible笔记(8):常用模块之系统类模块(二)
    ansible笔记(7):常用模块之系统类模块
    ansible笔记(6):常用模块之命令类模块
  • 原文地址:https://www.cnblogs.com/pwindy/p/16554251.html
Copyright © 2020-2023  润新知