您的位置:新葡亰496net > 新葡亰官网 > 新葡亰496net:javaScript承袭模式,JS的多种持续情

新葡亰496net:javaScript承袭模式,JS的多种持续情

发布时间:2019-06-19 08:36编辑:新葡亰官网浏览(161)

    JavaScript 多种持续方式

    2017/06/20 · JavaScript · 继承

    初稿出处: Xuthus Blog   

    连续是面向对象编制程序中又一不胜关键的概念,JavaScript扶助促成两次三番,不帮衬接口继承,实现三番五次首要凭借原型链来实现的。

    继续是面向对象编制程序中又一不行首要的概念,JavaScript扶助落到实处再三再四,不帮衬接口继承,达成持续主要依靠原型链来完结的。

    原型链承袭基本思维就是让贰个原型对象指向另三个档次的实例

    function SuperType() {
    this.property = true
    }
    SuperType.prototype.getSuperValue = function () {
    return this.property
    }
    function SubType() {
    this.subproperty = false
    }
    SubType.prototype = new SuperType()
    SubType.prototype.getSubValue = function () {
    return this.subproperty
    }
    var instance = new SubType()
    console.log(instance.getSuperValue()) // true

    代码定义了八个类型SuperType和SubType,每一种连串分别有五个性质和贰个办法,SubType承接了SuperType,而继续是经过创办SuperType的实例,并将该实例赋给SubType.prototype达成的。

    完毕的实质是重写原型对象,代之以一个新类型的实例,那么存在SuperType的实例中的全部属性和章程,以后也设有于SubType.prototype中了。

    我们驾驭,在创制一个实例的时候,实例对象中会有一个里边指针指向成立它的原型,举行关联起来,在这里代码SubType.prototype = new SuperType(),也会在SubType.prototype创造二个之中指针,将SubType.prototype与SuperType关联起来。

    所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会顺着那条链一贯往上找。

    拉长方式

    在给SubType原型增加方法的时候,借使,父类上也会有同一的名字,SubType将会覆盖这一个点子,达到重新的目标。 不过以此主意仍旧留存于父类中。

    切记不能够以字面量的花样充分,因为,下面说过通超过实际例继承本质上便是重写,再使用字面量情势,又是壹遍重写了,但此次重写未有跟父类有其余关系,所以就能够招致原型链截断。

    function SuperType() {
    this.property = true
    }
    SuperType.prototype.getSuperValue = function () {
    return this.property
    }
    function SubType() {
    this.subproperty = false
    }
    SubType.prototype = new SuperType()
    SubType.prototype = {
    getSubValue:function () {
    return this.subproperty
    }
    }
    var instance = new SubType()
    console.log(instance.getSuperValue()) // error

    问题

    仅仅的应用原型链承继,重要难题根源包罗引用类型值的原型。

    function SuperType() {
    this.colors = ['red', 'blue', 'green']
    }
    function SubType() {
    }
    SubType.prototype = new SuperType()
    var instance1 = new SubType()
    var instance2 = new SubType()
    instance1.colors.push('black')
    console.log(instance1.colors) // ["red", "blue", "green", "black"]
    console.log(instance2.colors) // ["red", "blue", "green", "black"]

    在SuperType构造函数定义了三个colors属性,当SubType通过原型链传承后,这么些特性就能够产出SubType.prototype中,就跟特意创立了SubType.prototype.colors同样,所以会导致SubType的享有实例都会共享这些天性,所以instance1修改colors这么些引用类型值,也会展示到instance2中。

    ECMAScript只协助落到实处三番五次(承继实际的主意),首要借助原型链来完毕。

    —————————————————————————————————————————————————————————

    原型链

    率先得要驾驭怎么是原型链,在一篇小说看懂proto和prototype的关联及界别中讲得极其详尽

    原型链承继基本观念正是让二个原型对象指向另三个类型的实例

    function SuperType() { this.property = true } SuperType.prototype.getSuperValue = function () { return this.property } function SubType() { this.subproperty = false } SubType.prototype = new SuperType() SubType.prototype.getSubValue = function () { return this.subproperty } var instance = new SubType() console.log(instance.getSuperValue()) // true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function SuperType() {
      this.property = true
    }
    SuperType.prototype.getSuperValue = function () {
      return this.property
    }
    function SubType() {
      this.subproperty = false
    }
    SubType.prototype = new SuperType()
    SubType.prototype.getSubValue = function () {
      return this.subproperty
    }
    var instance = new SubType()
    console.log(instance.getSuperValue()) // true

    代码定义了七个档期的顺序SuperType和SubType,各样品种分别有八本性质和贰个艺术,SubType承继了SuperType,而一连是经过创设SuperType的实例,并将该实例赋给SubType.prototype实现的。

    完成的面目是重写原型对象,代之以二个新类型的实例,那么存在SuperType的实例中的全数属性和方法,未来也存在于SubType.prototype中了。

    大家通晓,在创造壹个实例的时候,实例对象中会有一个之中指针指向创造它的原型,举办关联起来,在此处代码SubType.prototype = new SuperType(),也会在SubType.prototype创制一个内部指针,将SubType.prototype与SuperType关联起来。

    就此instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会沿着那条链一贯往上找。

    充分艺术

    在给SubType原型加多方法的时候,倘诺,父类上也许有同等的名字,SubType将会覆盖这几个方式,达到重新的目标。 不过这几个方法仍旧存在于父类中。

    难忘无法以字面量的花样丰裕,因为,下边说过通超过实际例传承本质上正是重写,再利用字面量方式,又是三遍重写了,但此次重写没有跟父类有其余关系,所以就能招致原型链截断。

    function SuperType() { this.property = true } SuperType.prototype.getSuperValue = function () { return this.property } function SubType() { this.subproperty = false } SubType.prototype = new SuperType() SubType.prototype = { getSubValue:function () { return this.subproperty } } var instance = new SubType() console.log(instance.getSuperValue()) // error

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function SuperType() {
      this.property = true
    }
    SuperType.prototype.getSuperValue = function () {
      return this.property
    }
    function SubType() {
      this.subproperty = false
    }
    SubType.prototype = new SuperType()
    SubType.prototype = {
      getSubValue:function () {
       return this.subproperty
      }
    }
    var instance = new SubType()
    console.log(instance.getSuperValue())  // error

    问题

    唯有的施用原型链承继,首要难点根源包蕴引用类型值的原型。

    function SuperType() { this.colors = ['red', 'blue', 'green'] } function SubType() { } SubType.prototype = new SuperType() var instance1 = new SubType() var instance2 = new SubType() instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"] console.log(instance2.colors) // ["red", "blue", "green", "black"]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function SuperType() {
      this.colors = ['red', 'blue', 'green']
    }
    function SubType() {
    }
    SubType.prototype = new SuperType()
    var instance1 = new SubType()
    var instance2 = new SubType()
    instance1.colors.push('black')
    console.log(instance1.colors)  // ["red", "blue", "green", "black"]
    console.log(instance2.colors) // ["red", "blue", "green", "black"]

    在SuperType构造函数定义了二个colors属性,当SubType通过原型链承袭后,这些本性就能冒出SubType.prototype中,就跟特意创设了SubType.prototype.colors同样,所以会导致SubType的有所实例都会共享这些天性,所以instance1修改colors那些引用类型值,也会呈现到instance第22中学。

    原型链

    借用构造函数

    此措施为了解决原型中蕴藏引用类型值所带来的标题。

    这种措施的思考就是在子类构造函数的内部调用父类构造函数,能够借助apply()和call()方法来改动指标的试行上下文

    function SuperType() {
    this.colors = ['red', 'blue', 'green']
    }
    function SubType() {
    // 继承SuperType
    SuperType.call(this)
    }
    var instance1 = new SubType()
    var instance2 = new SubType()
    instance1.colors.push('black')
    console.log(instance1.colors) // ["red", "blue", "green", "black"]
    console.log(instance2.colors) // ["red", "blue", "green"]

    在新建SubType实例是调用了SuperType构造函数,这样来讲,就能在新SubType目的上奉行SuperType函数中定义的全数目的开端化代码。

    结果,SubType的每一个实例就能够具备友好的colors属性的别本了。

    传递参数

    依靠构造函数还大概有八个优势正是能够传递参数

    function SuperType(name) {
    this.name = name
    }
    function SubType() {
    // 继承SuperType
    SuperType.call(this, 'Jiang')
    this.job = 'student'
    }
    var instance = new SubType()
    console.log(instance.name) // Jiang
    console.log(instance.job) // student

    问题

    假设单纯依赖构造函数,方法都在构造函数中定义,因而函数不能够达到规定的规范复用

    1、原型链

    继承 - ECMAScript只帮助促成持续(依据原型链),不扶助接口承接(函数未有具名)

    借用构造函数

    此措施为了缓和原型中蕴藏引用类型值所带来的主题材料。

    这种情势的想想正是在子类构造函数的内部调用父类构造函数,能够借助apply()和call()方法来改动指标的进行上下文

    function SuperType() { this.colors = ['red', 'blue', 'green'] } function SubType() { // 继承SuperType SuperType.call(this) } var instance1 = new SubType() var instance2 = new SubType() instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"] console.log(instance2.colors) // ["red", "blue", "green"]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function SuperType() {
      this.colors = ['red', 'blue', 'green']
    }
    function SubType() {
      // 继承SuperType
      SuperType.call(this)
    }
    var instance1 = new SubType()
    var instance2 = new SubType()
    instance1.colors.push('black')
    console.log(instance1.colors)  // ["red", "blue", "green", "black"]
    console.log(instance2.colors) // ["red", "blue", "green"]

    在新建SubType实例是调用了SuperType构造函数,那样的话,就能在新SubType指标上实行SuperType函数中定义的装有指标起初化代码。

    结果,SubType的每一种实例就聚会场全体温馨的colors属性的别本了。

    传递参数

    借助于构造函数还有二个优势便是能够传递参数

    function SuperType(name) { this.name = name } function SubType() { // 继承SuperType SuperType.call(this, 'Jiang') this.job = 'student' } var instance = new SubType() console.log(instance.name) // Jiang console.log(instance.job) // student

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function SuperType(name) {
      this.name = name
    }
    function SubType() {
      // 继承SuperType
      SuperType.call(this, 'Jiang')
     
      this.job = 'student'
    }
    var instance = new SubType()
    console.log(instance.name)  // Jiang
    console.log(instance.job)   // student

    问题

    只要单独依靠构造函数,方法都在构造函数中定义,由此函数不能达到规定的规范复用

    率先得要清楚什么是原型链,在一篇小说看懂proto和prototype的关系及界别中讲得可怜详尽

    组成承袭(原型链 构造函数)

    整合承接是将原型链传承和构造函数结合起来,从而发挥两岸之长的一种情势。

    思路就是选拔原型链完结对原型属性和办法的承接,而经过借用构造函数来达成对实例属性的持续。

    那般,既通过在原型上定义方法实现了函数复用,又能够有限支撑种种实例都有它本人的性质。

    function SuperType(name) {
    this.name = name
    this.colors = ['red', 'blue', 'green']
    }
    SuperType.prototype.sayName = function () {
    console.log(this.name)
    }
    function SubType(name, job) {
    // 承继属性
    SuperType.call(this, name)
    this.job = job
    }
    // 承接方法
    SubType.prototype = new SuperType()
    SubType.prototype.constructor = SuperType
    SubType.prototype.sayJob = function() {
    console.log(this.job)
    }
    var instance1 = new SubType('Jiang', 'student')
    instance1.colors.push('black')
    console.log(instance1.colors) //["red", "blue", "green", "black"]
    instance1.sayName() // 'Jiang'
    instance1.sayJob() // 'student'
    var instance2 = new SubType('J', 'doctor')
    console.log(instance2.colors) // //["red", "blue", "green"]
    instance2.sayName() // 'J'
    instance2.sayJob() // 'doctor'

    这种形式防止了原型链和构造函数承袭的久治不愈的疾病,融入了他们的独到之处,是最常用的一种持续方式。

    着力思维是使用原型让一个引用类型承继另三个引用类型的本性和办法。

    原型链

    组成承接(原型链 构造函数)

    重组传承是将原型链承袭和构造函数结合起来,从而发挥两岸之长的一种格局。

    思路就是运用原型链实现对原型属性和方式的持续,而透过借用构造函数来落到实处对实例属性的接轨。

    如此那般,既通过在原型上定义方法完结了函数复用,又能够确认保障每一种实例都有它本人的品质。

    function SuperType(name) { this.name = name this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name) } function SubType(name, job) { // 承继属性 SuperType.call(this, name) this.job = job } // 承继方法 SubType.prototype = new SuperType() SubType.prototype.constructor = SuperType SubType.prototype.sayJob = function() { console.log(this.job) } var instance1 = new SubType('Jiang', 'student') instance1.colors.push('black') console.log(instance1.colors) //["red", "blue", "green", "black"] instance1.sayName() // 'Jiang' instance1.sayJob() // 'student' var instance2 = new SubType('J', 'doctor') console.log(instance2.colors) // //["red", "blue", "green"] instance2.sayName() // 'J' instance2.sayJob() // 'doctor'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function SuperType(name) {
      this.name = name
      this.colors = ['red', 'blue', 'green']
    }
    SuperType.prototype.sayName = function () {
      console.log(this.name)
    }
    function SubType(name, job) {
      // 继承属性
      SuperType.call(this, name)
     
      this.job = job
    }
    // 继承方法
    SubType.prototype = new SuperType()
    SubType.prototype.constructor = SuperType
    SubType.prototype.sayJob = function() {
      console.log(this.job)
    }
    var instance1 = new SubType('Jiang', 'student')
    instance1.colors.push('black')
    console.log(instance1.colors) //["red", "blue", "green", "black"]
    instance1.sayName() // 'Jiang'
    instance1.sayJob()  // 'student'
    var instance2 = new SubType('J', 'doctor')
    console.log(instance2.colors) // //["red", "blue", "green"]
    instance2.sayName()  // 'J'
    instance2.sayJob()  // 'doctor'

    这种方式防止了原型链和构造函数字传送承的缺陷,融合了她们的亮点,是最常用的一种持续方式。

    原型链承继基本思量正是让叁个原型对象指向另八个品种的实例

    示例:

    • 使用原型让三个引用类型承继另叁个引用类型的习性和艺术,
    • 构造函数、原型、实例的关联:每一种构造函数都有三个原型对象,原型对象涵盖贰个针对构造函数的指针。实例包蕴三个对准原型对象的个中指针,在创制实例之后即针对原型对象
    • 而当A原型对象的指针指向B个原型对象时(此时A原型对象与B实例同级),就形成了一条原型链。
    • 图解:

      新葡亰496net 1

      原型寻觅机制:当读取方式访问三个实例属性时,首先会在实例中搜求该属性,借使未有找到该属性则沿着原型链向上查找

    原型式承接

    依赖原型能够依附已部分对象创立新指标,同有的时候间还不用因而成立自定义类型。

    function object(o) { function F() {} F.prototype = o return new F() }

    1
    2
    3
    4
    5
    function object(o) {
      function F() {}
      F.prototype = o
      return new F()
    }

    在object函数内部,先成立二个有时性的构造函数,然后将盛传的对象作为这些构造函数的原型,最终回到那几个不时类型的贰个新实例。

    实为上来讲,object对传播当中的靶子试行了二遍浅复制。

    var person = { name: 'Jiang', friends: ['Shelby', 'Court'] } var anotherPerson = object(person) console.log(anotherPerson.friends) // ['Shelby', 'Court']

    1
    2
    3
    4
    5
    6
    var person = {
      name: 'Jiang',
      friends: ['Shelby', 'Court']
    }
    var anotherPerson = object(person)
    console.log(anotherPerson.friends)  // ['Shelby', 'Court']

    这种方式要去你不能够不有三个指标作为另贰个对象的根基。

    在那么些例子中,person作为另多个对象的基本功,把person传入object中,该函数就可以回来叁个新的靶子。

    那几个新对象将person作为原型,所以它的原型中就隐含三个宗旨类型和多个引用类型。

    据此意味着一旦还恐怕有别的一个对象关联了person,anotherPerson修改数组friends的时候,也会反映在那些指标中。

    Object.create()方法

    ES5通过Object.create()方法标准了原型式承接,能够承受七个参数,四个是用作新对象原型的指标和三个可选的为新指标定义额外属性的靶子,行为无差别于,基本用法和方面的object同样,除了object无法接受第三个参数以外。

    var person = { name: 'Jiang', friends: ['Shelby', 'Court'] } var anotherPerson = Object.create(person) console.log(anotherPerson.friends) // ['Shelby', 'Court']

    1
    2
    3
    4
    5
    6
    var person = {
      name: 'Jiang',
      friends: ['Shelby', 'Court']
    }
    var anotherPerson = Object.create(person)
    console.log(anotherPerson.friends)  // ['Shelby', 'Court']

    function SuperType() {

      function SuperType(){
            this.property = true; //实例属性
        }
        SuperType.prototype.getSuperValue = function(){//原型方法
            return this.property;
        }

    在例子<Demo-1>中,调用instance.getSuperValue(),先搜索实例instance,再搜索SubType.prototype,再搜索SuperType.protorype,最后一步才找到该方法。
    
    默认的原型:所有的引用类型默认都继承了Object,所以默认原型的指针都会指向Object.prototype,完整的原型链如下:
    
    
    instance → SubType.prototype → SuperType.prototype → Object.prototype
    
    ![](https://images2017.cnblogs.com/blog/1146465/201707/1146465-20170731170706005-1605874342.png)
    

    寄生式承继

    寄生式承继的思绪与寄生构造函数和工厂形式类似,即开立二个仅用于封装传承进度的函数。

    function createAnother(o) { var clone = Object.create(o) // 创设多个新目的 clone.sayHi = function() { // 加多办法 console.log('hi') } return clone // 重临那几个目的 } var person = { name: 'Jiang' } var anotherPeson = createAnother(person) anotherPeson.sayHi()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function createAnother(o) {
      var clone = Object.create(o) // 创建一个新对象
      clone.sayHi = function() { // 添加方法
        console.log('hi')
      }
      return clone  // 返回这个对象
    }
    var person = {
      name: 'Jiang'
    }
    var anotherPeson = createAnother(person)
    anotherPeson.sayHi()

    依靠person再次来到了三个新目的anotherPeson,新对象不唯有有着了person的性质和方式,还会有温馨的sayHi方法。

    在重中之重思索对象而不是自定义类型和构造函数的情事下,那是贰个得力的格局。

      this.property = true

        function SubType(){
            this.subproperty = false;
        }
        
        //SubType继承了SuperType
        SubType.prototype = new SuperType();
        
        SubType.prototype.getSubValue = function(){
            return this.subproperty;
        }
        
        var instance = new SubType();
        console.log(instance.getSuperValue()); //true
        console.log(instance.constructor); //SuperType

    • p.s.

      总得替换掉实例的原型后本领给实例加多方法

    寄生组合式承袭

    在头里说的咬合方式(原型链 构造函数)中,承继的时候要求调用一次父类构造函数。

    父类

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

    1
    2
    3
    4
    function SuperType(name) {
      this.name = name
      this.colors = ['red', 'blue', 'green']
    }

    先是次在子类构造函数中

    function SubType(name, job) { // 承接属性 SuperType.call(this, name) this.job = job }

    1
    2
    3
    4
    5
    6
    function SubType(name, job) {
      // 继承属性
      SuperType.call(this, name)
     
      this.job = job
    }

    第四回将子类的原型指向父类的实例

    // 承袭方法 SubType.prototype = new SuperType()

    1
    2
    // 继承方法
    SubType.prototype = new SuperType()

    新葡亰496net,当使用var instance = new SubType()的时候,会生出两组name和color属性,一组在SubType实例上,一组在SubType原型上,只不超过实际例上的遮挡了原型上的。

    动用寄生式组合情势,能够避开这么些标题。

    这种形式通过借用构造函数来延续属性,通过原型链的混成格局来连续方法。

    基本思路:不必为了钦赐子类型的原型而调用父类的构造函数,大家要求的不过正是父类原型的三个别本。

    实质上正是应用寄生式承接来继续父类的原型,在将结果钦点给子类型的原型。

    function inheritPrototype(subType, superType) { var prototype = Object.create(superType.prototype) prototype.constructor = subType subType.prototype = prototype }

    1
    2
    3
    4
    5
    function inheritPrototype(subType, superType) {
      var prototype = Object.create(superType.prototype)
      prototype.constructor = subType
      subType.prototype = prototype
    }

    该函数完成了寄生组合承接的最轻巧易行款式。

    其一函数接受多个参数,贰个子类,三个父类。

    率先步创立父类原型的别本,第二步将开创的别本增添constructor属性,第三部将子类的原型指向这几个别本。

    function SuperType(name) { this.name = name this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name) } function SubType(name, job) { // 承继属性 SuperType.call(this, name) this.job = job } // 承接inheritPrototype(SubType, SuperType) var instance = new SubType('Jiang', 'student') instance.sayName()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function SuperType(name) {
      this.name = name
      this.colors = ['red', 'blue', 'green']
    }
    SuperType.prototype.sayName = function () {
      console.log(this.name)
    }
    function SubType(name, job) {
      // 继承属性
      SuperType.call(this, name)
     
      this.job = job
    }
    // 继承
    inheritPrototype(SubType, SuperType)
    var instance = new SubType('Jiang', 'student')
    instance.sayName()

    补充:直接使用Object.create来落到实处,其实正是将方面封装的函数拆开,那样演示能够更易于明白。

    function SuperType(name) { this.name = name this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name) } function SubType(name, job) { // 承继属性 SuperType.call(this, name) this.job = job } // 承接 SubType.prototype = Object.create(SuperType.prototype) // 修复constructor SubType.prototype.constructor = SubType var instance = new SubType('Jiang', 'student') instance.sayName()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function SuperType(name) {
      this.name = name
      this.colors = ['red', 'blue', 'green']
    }
    SuperType.prototype.sayName = function () {
      console.log(this.name)
    }
    function SubType(name, job) {
      // 继承属性
      SuperType.call(this, name)
     
      this.job = job
    }
    // 继承
    SubType.prototype = Object.create(SuperType.prototype)
    // 修复constructor
    SubType.prototype.constructor = SubType
    var instance = new SubType('Jiang', 'student')
    instance.sayName()

    ES6新扩展了七个方法,Object.setPrototypeOf,能够直接创立关联,而且不用手动增添constructor属性。

    // 继承 Object.setPrototypeOf(SubType.prototype, SuperType.prototype) console.log(SubType.prototype.constructor === SubType) // true

    1
    2
    3
    // 继承
    Object.setPrototypeOf(SubType.prototype, SuperType.prototype)
    console.log(SubType.prototype.constructor === SubType) // true

    1 赞 2 收藏 评论

    新葡亰496net 2

    }

    说明:

    不能使用对象字面量创建原型方法,这样做会重写原型链,如<Demo-3>
    

    SuperType.prototype.getSuperValue = function () {

      以上代码创造了四个品种:SuperType 和 SubType。那七个品种都有各自的品质和措施,SubType承接了SuperType,承继是通过创办SuperType的实例,并把该实例赋给SubType的prototype。完毕的精神是重写了SubType原型对象,代之以多个新品类的实例。

    • 缺点:

      富含引用类型值(Function Object Array)的原型属性会被抱有实例共享,在通过原型来落到实处再三再四时,原型实际上会产生另多少个类别的实例,所以本来的实例属性就改成了今后的原型属性了。<德姆o-4>

      在开立子类型的实例时,无法向超类型的构造函数中传送参数。

      // "use strict";

      // Demo - 1 // SuperType 具备一个属性和二个格局// SubType 具有三天质量和贰个方法,又从SuperType这里承继了二个性情二个办法 function SuperType(){

      this.property = "111";
      

      } SuperType.prototype.getSuperValue = function(){

      return this.property;
      

      } function SubType(){

      this.subproperty = "222";
      

      } // p.s.new操作在此之前,SubType.prototype指向的是function,不容许为function()定义.getSubValue方法,所以要将增进方法放在修改原型指向之后 // 操作之后SubType.prototype指向SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ // 必须在SubType替换原型之后能力定义

      return this.subproperty;
      

      } var instance = new SubType(); console.log(instance.property); // 111 console.log(instance.getSuperValue()); // 111 console.log(instance.subproperty); // 222 console.log(instance.getSubValue()); // 222 console.log(instance.constructor); // f SuperType(){} 原来SubType中的constructor属性被重写 // 重写SuperType.getSuperValue() // 若是要重写这么些办法,会遮掩原本的章程 // 换句话说,当通过SubType的实例调用getSuperValue时调用的正是以此重新定义的艺术,但通过SuperType的实例调用时还有或许会一连调用原本的不二诀窍var beforeReWrite = new SuperType(); SuperType.prototype.getSuperValue = function(){

      console.log("rewrite");
      

      } console.log(instance.getSuperValue()); // rewrite,this.property = undefined console.log(SuperType.prototype.getSuperValue()); // rewrite,this.property = undefined console.log(beforeReWrite.getSuperValue());

      // Demo - 2 // 确认原型和实例的涉及 console.log(instance instanceof Object); // true console.log(instance instanceof SuperType); // true console.log(instance instanceof SubType); // true // 另一种艺术 console.log(Object.prototype.isPrototypeOf(instance)); // true console.log(SuperType.prototype.isPrototypeOf(instance)); // true console.log(SubType.prototype.isPrototypeOf(instance)); // true

      // Demo - 3 function SuperType2(){

      this.property = "1111";
      

      } SuperType2.prototype.getSuperValue = function(){

      return this.property;
      

      } function SubType2(){

      this.subproperty = "2222";
      

      } SubType2.prototype = new SuperType2(); SubType2.prototype = {

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

      } var instance2 = new SubType2(); console.log(instance2 instanceof Object); // true console.log(instance2 instanceof SuperType2); // false,原型链被隔绝console.log(instance2 instanceof SubType2); // true // console.log(instance2.getSuperValue()); // error

      // Demo - 4 function SuperType3(){

      this.colors = ["red","blue","green"];
      

      } function SubType3(){} SubType3.prototype = new SuperType3(); var instance3 = new SubType3(); instance3.colors.push("black"); console.log(instance3.colors); // ["red", "blue", "green", "black"] var instance4 = new SubType3(); console.log(instance4.colors); // ["red", "blue", "green", "black"]

      return this.property

      SubType的新原型具有SuperType全体的性质和措施,同不时候其里面还可能有二个指针[[Prototype]],指向SuperType的原型,最后结出是instance指向了SubType的原型,SubType的原型又针对了SuperType的原型。

     

    }

      instance.constructor指向的是SuperType,那是因为原来的SubType.prototype中的constructor被重写了。(实际上不是SubType的原型的constructor属性被重写了,而是SubType的原型指向了SuperType,而以此原型的constructor属性指向的是SuperType。)

    借用构造函数(伪造对象 / 杰出两次三番)

    function SubType() {

      全部引用类型暗中同意都持续了Object,那个延续也是经过原型链类完结的。全体函数的暗中认可原型都以Object的实例,暗许原型都会含有三个里头指针,指向Object.prototype。

    • 在子类型构造函数的里边调用超类型构造函数
    • 优点:

      化解了独自使用原型链共享引用类型值属性的标题

      this.subproperty = false

     

    可以在子类型构造函数中向超类型构造函数传递参数
    

    }

    新葡亰496net 3

    • 缺点:

      不或然幸免构造函数形式存在的标题:方法都在构造函数中定义,不能够落到实处函数复用

      // "use strict";

      function SuperType(name) {

      this.name = name;
      this.colors = ["111", "222", "333"];
      

      }

      function SubType() {

      SuperType.call(this, "name1");
      this.age = 20;
      

      }

      var instance = new SubType(); instance.colors.push("444"); console.log(instance.colors); // ["111", "222", "333", "444"] console.log(instance.name); // name1 console.log(instance.age); // 20 var instance2 = new SubType(); console.log(instance2.colors); // ["111", "222", "333"]

    SubType.prototype = new SuperType()

    留神:在通过原型链实现持续时,不能够使用字面量对象创立原型方法,那样会重写原型链,把大家的原型链切断。

     

    SubType.prototype.getSubValue = function () {

    原型链的标题:(1)、包蕴引用类型值的原型;

    重组承袭(伪优良承接)

      return this.subproperty

                        (2)、创造子类型的实例时,无法向超类型的构造函数中传递参数。

    • 将原型链和借用构造函数组合,使用原型链实现对原型属性和方法的继续,通过借用构造函数来贯彻对实例属性的连续
    • 对应创造对象 <组合使用构造函数形式和原型方式>
    • 优点:最常用
    • 缺陷:供给调用一遍超类型构造函数,三回在开立子函数原型时,另一遍在子函数构造函数内部。调用子类型构造函数时索要重写属性

      // "use strict"; function SuperType(name) {

      this.name = name;
      this.colors = ["111", "222", "333"];
      

      } SuperType.prototype.sayName = function() {

      console.log(this.name);
      

      }

      function SubType(name, age) {

      SuperType.call(this, name); // 继承属性
      this.age = age;
      

      } SubType.prototype = new SuperType(); // 承袭方法 SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() {

      console.log(this.age);
      

      } var instance1 = new SubType("hugh", 20); instance1.colors.push("444"); console.log(instance1.colors); // ["111", "222", "333", "444"] instance1.sayName(); // hugh instance1.sayAge(); // 20 var instance2 = new SubType("dong", 21); console.log(instance2.colors); // ["111", "222", "333"] instance2.sayName(); // dong instance2.sayAge(); // 21

    }

    2、借用构造函数

     

    var instance = new SubType()

    也叫伪造对象或许优秀再而三,基本思维是在子类型构造函数内部调用超类型构造函数。

    原型式承接

    console.log(instance.getSuperValue()) // true

       function SuperType(name){
            this.name = name;
            this.colors = ['red', 'blue', 'green'];
        }
        
        function SubType(){
            //承继了SubType,同临时候还传递了参数
            SuperType.call(this, 'Nick');
            
            //实例属性
            this.age = 12;
        }
        
        var instance1 = new SubType();
        instance1.colors.push('gray');
        console.log(instance1.name);
        console.log(instance1.age);
        
        var instance2 = new SubType();
        console.log(instance2.colors);

    • 对应创立对象 <动态原型方式>
    • 从没应用严峻意义上的构造函数,借助已部分对象创制新对象
    • 优点:

      在不想创设构造函数,只想让一个对象与另一个对象保障类似的情状下,原型式承继完全能够胜任

    代码定义了几个类型SuperType和SubType,每一个体系分别有壹本性质和贰个方式,SubType承继了SuperType,而延续是经过创建SuperType的实例,并将该实例赋给SubType.prototype达成的。

    借用构造函数的标题:方法都在构造函数中定义,因而函数复用就不能提及了。而且,在超类型的原型中定义的艺术,对子类型来说也是不可知的。

    • 缺点:

      包括引用类型值的质量始终都会共享,就像是原型方式同样

      // "use strict"; function object(o){

      function F(){} // 创建临时性构造函数
      F.prototype = o; // 将传入的对象作为构造函数的原型
      return new F(); // 返回临时类型的一个新实例
      

      }

      var person = {

      name:"hugh",
      friends:["111",'222','333']
      

      };

      var anotherPerson = object(person); anotherPerson.name = "dong"; anotherPerson.friends.push("444");

      var yetAnotherPerson = object(person); yetAnotherPerson.name = "hehe"; yetAnotherPerson.friends.push("555");

      console.log(person.friends); // ["111", "222", "333", "444", "555"] console.log(person.name); // hugh console.log(anotherPerson.friends); // ["111", "222", "333", "444", "555"] console.log(anotherPerson.name); // dong console.log(yetAnotherPerson.friends); // ["111", "222", "333", "444", "555"] console.log(yetAnotherPerson.name); // hehe

      // 使用Object.create()标准化原型式继承// 以这种方式钦赐的别的性质都会覆盖原型对象上的同名属性 var otherPerson1 = Object.create(person); otherPerson1.friends.push("666"); console.log(yetAnotherPerson.friends); // ["111", "222", "333", "444", "555", "666"] var otherPerson2 = Object.create(person,{

      name:{
          value:"test"
      }
      

      }); console.log(otherPerson2.name);

    达成的实质是重写原型对象,代之以贰个新类型的实例,那么存在SuperType的实例中的全部属性和方法,将来也存在于SubType.prototype中了。

    3、组合承袭

     

    大家掌握,在开立一个实例的时候,实例对象中会有一个里边指针指向创设它的原型,举办关联起来,在那边代码SubType.prototype = new SuperType(),也会在SubType.prototype创建三个内部指针,将SubType.prototype与SuperType关联起来。

    也叫伪优良三番四次,基本思想是采取原型链完成对原型属性和艺术的一连,通过借用构造函数达成对实例属性的接续,那样,即通过在原型上定义方法完结了函数复用,又能确定保证每种实例都有它和谐的天性。

    寄生式承接新葡亰496net:javaScript承袭模式,JS的多种持续情势。

    据此instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会沿着那条链一贯往上找。

       function SuperType(name){
            this.name = name;
            this.colors = ['red', 'yellow', 'blue'];
        }
        
        SuperType.prototype.sayName = function(){
            return this.name;
        }
        
        function SubType(name, age){
            //承袭属性
            SuperType.call(this, name);
            this.age = age;
        }
        //承袭方法
        SubType.prototype = new SuperType();
        
        SubType.prototype.sayAge = function(){
            return this.age;
        }
        
        var instance1 = new SubType('Tom', 12);
        instance1.colors.push('black');
        console.log(instance1.colors);//['red', 'yellow', 'blue', 'black']
        console.log(instance1.sayAge());//12
        console.log(instance1.sayName());//Tom
        
        var instance2 = new SubType('Lucy',21);
        console.log(instance2.colors);//['red', 'yellow', 'blue']
        console.log(SubType.prototype.isPrototypeOf(instance2));//true
        console.log(SuperType.prototype.isPrototypeOf(instance2));//true

    • 对应创设对象 <寄生构造函数 / 工厂格局>
    • 创设一个仅用于封装承袭进程的函数,在内部抓实对象,最终回到对象
    • 以身作则集成形式时接纳的object()函数不是必须的,任何能够回来新对象的函数都适用于此格局
    • 新葡亰496net:javaScript承袭模式,JS的多种持续情势。接纳境况:在重大思考对象而不是自定义类型和构造函数的地方下,寄生式承接也是一种有效的形式
    • 症结:不可能到位函数复用,类似于构造函数格局

      // "use strict"; function object(o) {

      function F() {} // 创建临时性构造函数
      F.prototype = o; // 将传入的对象作为构造函数的原型
      return new F(); // 返回临时类型的一个新实例
      

      }

      function createAnother(original) { // 接收的函数作为新对象基础的对象

      var clone = object(original);
      clone.sayHi = function() { // 添加新方法
          console.log('hi');
      };
      return clone;
      

      } var person = {

      name: "hugh",
      friends: ['111', '222', '333']
      

      }; var person1 = createAnother(person); person1.sayHi(); console.log(person1.name); console.log(person1.friends);

    累加艺术

    重组承接是JavaScript常用的接轨形式,可是也是有欠缺。

     

    在给SubType原型增多方法的时候,如若,父类上也是有一致的名字,SubType将会覆盖那一个艺术,达到重新的指标。 不过以此格局照旧留存于父类中。

     4、寄生组合式承接

    寄生组合式承继

    切记不可能以字面量的样式丰硕,因为,下边说过通超过实际例承袭本质上正是重写,再使用字面量格局,又是贰回重写了,但此番重写没有跟父类有任何关系,所以就能导致原型链截断。

    由此借用构造函数来承接属性,通过原型链的混成格局来持续方法。

    • 优点:

      最精良的后续范式

      消除组合承袭重写属性的主题素材,只调用了三遍SuperType构造函数

      制止了在SubType.prototype上成立不须求的个性

      原型链保持不改变

      可以平常使用instanceof和isPrototypeOf()

      "use strict"; function object(o) {

      function F() {}
      F.prototype = o;
      return new F();
      

      }

      // 1.创造超类型原型的一个别本// 2.为开创的别本增加constructor属性,弥补因重写原型而失去的天性// 3.将新创设的指标(即别本)赋值给子类型的原型 function inheritProtoType(subType,superType){

      var prototype = object(superType.prototype); // 创建对象
      prototype.constructor = subType; // 增强对象
      subType.prototype = prototype; // 指定对象
      

      } function SuperType(name){

      this.name = name;
      this.colors= [1,2,3,4];
      

      } SuperType.prototype.sayName = function(){

      console.log(this.name);
      

      } function SubType(name,age){

      SuperType.call(this,name);
      this.age = age;
      

      } inheritProtoType(SubType,SuperType); SubType.prototype.sayAge = function(){

      console.log(this.age);
      

      }

    function SuperType() {

        //借助原型基于已有指标创制新对象(本质上讲,object()对传播的靶子实施了一次浅复制)
        function object(o){
            function F(){}
            F.prototype = o;
            return new F();
        }
        //使用寄生式承袭来接二连三超类型的原型,然后再将结果钦点给子类型的原型
        function inheritPrototype(SuperType, SubType){
            var prototype = object(SuperType.prototype);//创造超类型原型的二个别本
            prototype.constructor = SubType;//加强对象,弥补因重写原型而错过的暗许的constructor属性
            SubType.prototype = prototype;
        }

    新葡亰496net 4

      this.property = true

        function SuperType(name){
            this.name = name;
            this.colors = ['blue', 'red', 'green'];
        }
        
        SuperType.prototype.sayName = function(){
            return this.name;
        }
        
        function SubType(name, age){
            SuperType.call(this, name);
            this.age = age;
        }
        
        inheritPrototype(SuperType, SubType);
        
        SubType.prototype.sayAge = function(){
            return this.age;
        }
        
        var instance = new SubType('Tom', 12);
      instance.colors.push('black');
      console.log(instance.colors);
      delete instance.name;
      console.log(instance.name);

    }

      var instance = new SubType('Lucy', 33);
      console.log(instance.colors);

    SuperType.prototype.getSuperValue = function () {

    广泛以为寄生组合式承接是援引类型最特出的存在延续范式。

      return this.property

    }

    function SubType() {

      this.subproperty = false

    }

    SubType.prototype = new SuperType()

    SubType.prototype = {

      getSubValue:function () {

      return this.subproperty

      }

    }

    var instance = new SubType()

    console.log(instance.getSuperValue())  // error

    问题

    单纯的利用原型链承接,首要难点源于包括引用类型值的原型。

    function SuperType() {

      this.colors = ['red', 'blue', 'green']

    }

    function SubType() {

    }

    SubType.prototype = new SuperType()

    var instance1 = new SubType()

    var instance2 = new SubType()

    instance1.colors.push('black')

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

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

    在SuperType构造函数定义了三个colors属性,当SubType通过原型链承袭后,那么些本性就能够冒出SubType.prototype中,就跟专门创造了SubType.prototype.colors同样,所以会促成SubType的具有实例都会共享那么些天性,所以instance1修改colors这一个引用类型值,也会突显到instance第22中学。

    借用构造函数

    此办法为了消除原型中带有引用类型值所推动的难点。

    这种方法的思维正是在子类构造函数的里边调用父类构造函数,能够借助apply()和call()方法来改动指标的推行上下文

    function SuperType() {

      this.colors = ['red', 'blue', 'green']

    }

    function SubType() {

      // 继承SuperType

      SuperType.call(this)

    }

    var instance1 = new SubType()

    var instance2 = new SubType()

    instance1.colors.push('black')

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

    console.log(instance2.colors) // ["red", "blue", "green"]

    在新建SubType实例是调用了SuperType构造函数,那样以来,就能够在新SubType目的上实行SuperType函数中定义的具有指标早先化代码。

    结果,SubType的各种实例就能够具有本人的colors属性的别本了。

    传递参数

    重视构造函数还应该有二个优势便是足以传递参数

    function SuperType(name) {

      this.name = name

    }

    function SubType() {

      // 继承SuperType

      SuperType.call(this, 'Jiang')

      this.job = 'student'

    }

    var instance = new SubType()

    console.log(instance.name)  // Jiang

    console.log(instance.job)  // student

    问题

    例如只是依附构造函数,方法都在构造函数中定义,因而函数无法完结复用

    结合承继(原型链 构造函数)

    组成承继是将原型链承继和构造函数结合起来,从而发挥双方之长的一种情势。

    思路正是应用原型链完毕对原型属性和艺术的持续,而由此借用构造函数来实现对实例属性的后续。

    如此,既通过在原型上定义方法达成了函数复用,又能够保障每个实例都有它和睦的习性。

    function SuperType(name) {

      this.name = name

      this.colors = ['red', 'blue', 'green']

    }

    SuperType.prototype.sayName = function () {

      console.log(this.name)

    }

    function SubType(name, job) {

      // 承接属性

      SuperType.call(this, name)

      this.job = job

    }

    // 承袭方法

    SubType.prototype = new SuperType()

    SubType.prototype.constructor = SuperType

    SubType.prototype.sayJob = function() {

      console.log(this.job)

    }

    var instance1 = new SubType('Jiang', 'student')

    instance1.colors.push('black')

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

    instance1.sayName() // 'Jiang'

    instance1.sayJob()  // 'student'

    var instance2 = new SubType('J', 'doctor')

    console.log(instance2.colors) // //["red", "blue", "green"]

    instance2.sayName()  // 'J'

    instance2.sayJob()  // 'doctor'

    这种情势制止了原型链和构造函数承继的重疾,融入了她们的亮点,是最常用的一种持续方式。

    原型式承袭

    依赖原型能够依据已有的对象成立新目的,同一时间还不必由此成立自定义类型。

    function object(o) {

      function F() {}

      F.prototype = o

      return new F()

    }

    在object函数内部,先创立一个不经常的构造函数,然后将盛传的指标作为那些构造函数的原型,最后回到这几个一时类型的一个新实例。

    真相上来讲,object对传播个中的对象试行了一回浅复制。

    var person = {

      name: 'Jiang',

      friends: ['Shelby', 'Court']

    }

    var anotherPerson = object(person)

    console.log(anotherPerson.friends)  // ['Shelby', 'Court']

    这种格局要去你不可能不有三个指标作为另二个目的的基础。

    在这些例子中,person作为另八个指标的功底,把person传入object中,该函数就能够重返多个新的目的。

    本条新对象将person作为原型,所以它的原型中就含有二个主干项目和七个引用类型。

    由此意味着一旦还有其它一个目的关系了person,anotherPerson修改数组friends的时候,也会映将来这几个指标中。

    Object.create()方法

    ES5由此Object.create()方法标准了原型式承接,勉强接受多个参数,多个是用作新对象原型的靶子和二个可选的为新对象定义额外属性的对象,行为一点差距也未有于,基本用法和上边的object同样,除了object不能够经受第四个参数以外。

    var person = {

      name: 'Jiang',

      friends: ['Shelby', 'Court']

    }

    var anotherPerson = Object.create(person)

    console.log(anotherPerson.friends)  // ['Shelby', 'Court']

    寄生式承接

    寄生式继承的思绪与寄生构造函数和工厂情势类似,即开立多个仅用于封装承袭进程的函数。

    function createAnother(o) {

      var clone = Object.create(o) // 制造二个新目的

      clone.sayHi = function() { // 增添办法

        console.log('hi')

      }

      return clone  // 再次来到这一个指标

    }

    var person = {

      name: 'Jiang'

    }

    var anotherPeson = createAnother(person)

    anotherPeson.sayHi()

    依照person重回了二个新对象anotherPeson,新目的不止全体了person的品质和章程,还大概有温馨的sayHi方法。

    在主要记挂对象而不是自定义类型和构造函数的事态下,那是多少个实用的格局。

    寄生组合式承继

    在前头说的三结合情势(原型链 构造函数)中,承接的时候须要调用一回父类构造函数。

    父类

    function SuperType(name) {

      this.name = name

      this.colors = ['red', 'blue', 'green']

    }

    先是次在子类构造函数中

    function SubType(name, job) {

      // 承接属性

      SuperType.call(this, name)

      this.job = job

    }

    其次次将子类的原型指向父类的实例

    // 承继方法

    SubType.prototype = new SuperType()

    当使用var instance = new SubType()的时候,会生出两组name和color属性,一组在SubType实例上,一组在SubType原型上,只可是实例上的遮挡了原型上的。

    应用寄生式组合形式,能够规避那一个主题素材。

    这种方式通过借用构造函数来一连属性,通过原型链的混成方式来三番陆次方法。

    基本思路:不必为了钦命子类型的原型而调用父类的构造函数,大家要求的只是正是父类原型的三个别本。

    实质上正是行使寄生式承继来继续父类的原型,在将结果钦赐给子类型的原型。

    function inheritPrototype(subType, superType) {

      var prototype = Object.create(superType.prototype)

      prototype.constructor = subType

      subType.prototype = prototype

    }

    该函数完结了寄生组合承接的最简便易行款式。

    这几个函数接受多少个参数,多少个子类,叁个父类。

    首先步创设父类原型的别本,第二步将创制的别本加多constructor属性,第三部将子类的原型指向那几个别本。

    function SuperType(name) {

      this.name = name

      this.colors = ['red', 'blue', 'green']

    }

    SuperType.prototype.sayName = function () {

      console.log(this.name)

    }

    function SubType(name, job) {

      // 承接属性

      SuperType.call(this, name)

      this.job = job

    }

    // 继承

    inheritPrototype(SubType, SuperType)

    var instance = new SubType('Jiang', 'student')

    instance.sayName()

    填补:直接行使Object.create来贯彻,其实正是将地点封装的函数拆开,那样演示能够更易于明白。

    function SuperType(name) {

      this.name = name

      this.colors = ['red', 'blue', 'green']

    }

    SuperType.prototype.sayName = function () {

      console.log(this.name)

    }

    function SubType(name, job) {

      // 承袭属性

      SuperType.call(this, name)

      this.job = job

    }

    // 继承

    SubType.prototype = Object.create(SuperType.prototype)

    // 修复constructor

    SubType.prototype.constructor = SubType

    var instance = new SubType('Jiang', 'student')

    instance.sayName()

    ES6新添了三个情势,Object.setPrototypeOf,能够向来创立关联,而且不用手动增多constructor属性。

    // 继承

    Object.setPrototypeOf(SubType.prototype, SuperType.prototype)

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

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:新葡亰496net:javaScript承袭模式,JS的多种持续情

    关键词: