原型链继承,构造函数继承,组合式继承,寄生式组合继承

133 阅读2分钟

一、准备代码

        var Parent = function() {
            this.name = '父亲的名字'
        }
        Parent.prototype.getName = function() {
            return this.name
        }

        var Child = function() {

        }

二、原型链继承

原理:将ChildprototypeParent实例关联起来 Child就可以直接拿到Parent里面的东西了

关键代码:

        Child.prototype = new Parent()
        Child.prototype.construct = Child

实验一下:


        var child = new Child()
        console.log(child.name)// 输出 父亲的名字
        console.log(child.getName) //输出 父亲的名字

很明显,Child的实例拿到了Parent里的东西。

原型链继承缺点

原型链继承虽然拿到里面的东西,但是当Parent里面的值是引用类型时,实例改变了引用对象里值时,其他实例拿到的值也会改变

实验一下:

中的代码修改一下:

        var Parent = function() {
            this.name = {
                fatherName: '父亲的名字'
            }
        }
        Parent.prototype.getName = function() {
            return this.name
        }

        var Child = function() {

        }
        
        var child = new Child()
        console.log(child.name)
        console.log(child.getName)

        var child1 = new Child()
        var child2 = new Child()
        child2.name.fatherName = 'child2 name'
        console.log(child1.name.fatherName) // child1.name.fatherName 的值随着改变

二、构造函数继承

将这行代码更改到上面 :

        var Child = function() {
            Parent.call(this, 'Child name')
        }
    

结果:


        var child1 = new Child()
        var child2 = new Child()
        child1.name.fatherName = 'child1 name'
        child2.name.fatherName = 'child2 name'
        console.log(child1.name.fatherName) // child1 name
        console.log(child2.name.fatherName) // child2 name
        console.log(child2.getName()) // 报错

构造函数继承缺点

构造函数继承 能够拿到 Parent 的属性,并且不会更改其他实例的拿到的数据。但是缺点也很明显: 这个方法拿不到 Parent.prototype 上面的方法。

三、组合式继承

顾名思义:将上面两种方法结合起来:这样既可以用 原型链继承 得到属性,也可以用 构造函数继承 得到方法。

        var Parent = function() {
            this.name = {
                fatherName: '父亲的名字'
            }
        }
        Parent.prototype.getName = function() {
            return this.name
        }

        var Child = function() {
            Parent.call(this, 'Child name')
        }
        Child.prototype = new Parent()
        Child.prototype.construct = Child
        
        
        var child1 = new Child()
        var child2 = new Child()
        child2.name.fatherName = 'child2 name'
        child1.name.fatherName = 'child1 name'
        console.log(child1.name.fatherName)
        console.log(child2.name.fatherName)
        console.log(child2.getName()) // {fatherName: "child2 name"}

组合式继承缺点

但是这样又会有个新的问题,每一次创建Child的实例时,就会new Parent(),很显然这样会造成资源的浪费。

四、寄生组合式继承

寄生组合式继承实现方法:

 Child.prototype = new Parent()
 改为:
 Child.prototype = Parent.prototype
 

因为 Parent的实例中的__proto__里面有Parentprototype,所以这样做就解决了组合式继承的缺点

寄生组合式缺点:

很明显,如果这样做,会导致如果我们只想使用Parent的时候,会看到Child往里面添加的方法,所以每个构造函数都要持有自己的专有的prototype对象

修改寄生组合式缺点:

        Child.prototype = Object.create(Parent.prototype)

通过创建一个新的中间对象,将该对象的prototype指向Parent.prototype,这样做避免了调用Patent的构造方法产生对象,又可以使Child能够访问到Prarent的prototype,并且,如果Child.prototype添加了属性、方法,也只会挂在这个中间对象的prototype上面,并不会影响到构造函数的prototype