美文网首页
继承的方法

继承的方法

作者: 以手画圆心 | 来源:发表于2018-03-06 19:52 被阅读7次

    1.原型链继承

    每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针(constructor),而每个实例都包含一个指向原型对象的内部指针(proto).
    实现原型链继承的基本模式:

            //定义第一个类型
            function FirstFun() {
                this.num = 1
            }
            //第一个类型定义方法
            FirstFun.prototype.getFirstNum = function() {
                console.log(this.num);
            }
            //定义第二个类型
            function SecondFun() {
                this.numb = 2
            }
            //继承第一个类型
            SecondFun.prototype = new FirstFun()
            //第二个类型定义方法
            SecondFun.prototype.getSecondNum = function() {
                console.log(this.numb)
            }
            //第二个类型添加实例
            var numbers = new SecondFun()
            //调用实例继承来的方法
            numbers.getFirstNum()
            //结果打印为:1
    

    原型链继承需注意:
    (1)别忘记默认原型:
    所有函数的默认原型都是object的实例。因此所有默认原型都会包含一个内部指针,指向object.prototype,这也是所有自定义类型都会继承toString()、valueOf()等默认方法的根本原因。
    (2)确定原型和实例的方法
    第一个:instanceof

    alert(numbers instanceof Object)     //true
    alert(numbers instanceof FirstFun)   //true
    alert(numbers instanceof SecondFun)  //true
    

    第二个:isPrototypeOf()

    alert(Object.prototype.isPrototype(numbers))  //true
    alert(FirstFun.prototype.isPrototype(numbers))  //true
    alert(SecondFun.prototype.isPrototype(numbers))  //true
    

    (3)谨慎定义方法:
    给原型添加方法的代码一定要在替换原型的语句之后。
    还有,再通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会重写原型链。

    (4)原型链存在的问题:

    第一个问题:
    引用类型值的原型属性,会被所有实例共享,这正是为什么要在构造函数中,而不是在原型上定义属性的原因。

            function Obj1() {
                this.colors = ["red","blue","yellow"]
            }
    
            function Obj2() {
            }
    
            Obj2.prototype = new Obj1()
    
            var test1 = new Obj2()
            test1.colors.push("green")
            console.log(test1.colors)  //["red","blue","yellow","green"]
    
            var test2 = new Obj2
            console.log(test2.colors)  //["red","blue","yellow","green"]
    

    第二个问题:
    没办法在不影响所有对象实例的情况下,向超类型的构造函数中传递参数。

    2.借用构造函数(有时候也叫伪造对象或者经典继承)

    基本思想:在子类型构造函数内部调用超类型构造函数。

    函数只不过是在特定环境中执行代码的对象,因此通过使用apply()或者call()方法也可以在(将来)新创建的对象上执行构造函数。

            function Obj1() {
                this.colors = ["red","blue","yellow"]
            }
    
            function Obj2() {
                Obj1.apply(this)
            }
    
            var test1 = new Obj2()
            test1.colors.push("green")
            console.log(test1.colors)  //["red","blue","yellow","green"]
    
            var test2 = new Obj2
            console.log(test2.colors)  //["red","blue","yellow"]
    
    借用构造函数继承优缺点:

    (1)优点:可以在子类型构造函数中向超类型构造函数传递参数。

            function Obj1(name) {
                this.name = name
            }
    
            function Obj2() {
                //继承了Obj1,同时传递了参数
                Obj1.call(this, "Peter")
                this.age = 28
            }
    
            var test1 = new Obj2()
            console.log(test1.name)  //Peter
            console.log(test1.age)   //28
    

    (2)缺点:方法都在构造函数中定义,因此函数复用就无从谈起。

    3.组合继承(也叫伪经典继承)

    思路:
    通过使用原型链实现対原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。

            function Obj1(name) {
                this.name = name
                this.colors = ['aaa','bbb','ccc']
            }
    
            Obj1.prototype.sayName = function() {
                console.log(this.name);
            }
    
            function Obj2(name, age) {
                //继承属性
                Obj1.call(this, name)
                // 添加新的属性
                this.age = age
            }
    
            //继承方法
            Obj2.prototype = new Obj1()
    
            //弥补因重写原型失去的constructor属性
            Obj2.prototype.constructor = Obj2
    
            //添加新的方法
            Obj2.prototype.sayAge = function() {
                console.log(this.age);
            }
    
            var test1 = new Obj2('Peter', 28)
            test1.colors.push('ddd')
            console.log(test1.colors)
            test1.sayName()
            test1.sayAge()
    
            var test2 = new Obj2('Greo', 33)
            console.log(test2.colors)
            test2.sayName()
            test2.sayAge()
    
    image.png

    优点:组合继承避免了原型链与借用构造函数继承的缺陷,融合入了他们的优点。
    缺点:无论在什么情况下,都会调用两次超类型构造函数。一次在创建子类型原型的时候,一次在子类型构造函数内部。

    4.寄生式继承

    基本思路:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。
    寄生式继承模式:

            function createAnother(original) {
                var clone = Object.create(original)
                clone.sayHi = function() {
                    alert("hi")
                }
                return clone
            }
    
            var person = {
                name:"Daiv",
                friends:["one","two","three"]
            }
    
            var anotherPerson = createAnother(person)
    
            anotherPerson.sayHi()
    

    5.寄生组合式继承

    所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
    基本思路:
    不必为了指定子类型的原型而调用超类型的构造函数,我们需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
    基本模式如下:

    //obj1是子类型结构,obj2是超类型结构
    function inheritPrototype(obj1, obj2){
      //第一步:创建超类型原型副本
      var prototype = object(obj2.prototype)
      //第二步:为创建的副本添加constructor属性,弥补因为重写原型而失去的默认的constructor属性
      prototype.constructor = obj1
      //第三步:将新创建的对象(即副本),赋值给子类型的原型
      obj1.prototype = prototype
    }
    
    function SuperType(name){
      this.name = name
      this.colors = ["red","blue","green"]
    }
    
    SuperType.prototype.sayName = function(){
      alert(this.name)
    } 
    
    function SubType(name,age){
      SuperType.call(this,name)
      this.age = age
    }
    
    inheritPrototype(SubType,SuperType)
    
    SubType.prototype.sayAge = function(){
      alaert(this.age)
    }
    

    相关文章

      网友评论

          本文标题:继承的方法

          本文链接:https://www.haomeiwen.com/subject/mmrxfftx.html