javascript之继承

主要是参考了《JavaScript高级程序设计(第三版)》这本书,根据自己的理解,做了下面的记录

 

继承是面向对象(OO)语言里面的概念,有俩种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。由于函数没有签名,在javascript里面无法实现接口继承,只支持实现继承。

原型链继承

   构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

  

   所有函数的默认原型都是Object的实例

   那如果让原型对象等于另一个类型的实例会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型也包含着指向另一个构造函数的指针。

   具体代码: 

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

判断原型和实例的关系

使用instance或者isPrototypeOf

1     alert(instance instanceof SubType)  //  true
2     alert(SubType.prototype.isPrototypeOf(instance))  // true

 

缺点:

 (一)、只要某个实例、构造函数、原型对象修改了属性或方法,会对原型链上的其他对象实例造成影响

 (二)、在创建了类型的实例时,没有办法在不影响谁有对象实例的情况下,给超类型的构造函数传递参数

 

借用构造函数

    

 1     function SuberType() {
 2       this.colors = ["red","blur"]
 3     }
 4     function SubType() {
 5       //继承了SuberType 
 6       //使用了call改变了this的作用域,用apply也可以
 7       SuberType.call(this)
 8     }
 9     var instance = new  SubType()
10     instance.colors.push("black")
11     alert(instance.colors) //red,blur,black
13 var instalce2 = new SuberType() 14 alert(instalce2.colors) // red,blur

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

 1      function SuberType(name) {
 2         this.name = name
 3       }
 4       function SubType() {
 5         //继承了SuberType,还传递了参数
 6         SuberType.call(this,"zhao")
 7         this.age = "27"
 8       }
 9       var instance = new SubType()
10       alert(instance.name) //zhao
11       alert(instance.age) //27

缺点:

方法都在构造函数中定义,函数无法复用。而且在超类型的原型中定义的方法,子类型是不可见的

 

组合继承

     原型链和构造函数的技术组合到一起。思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

     

 1    function SuberType(name) {
 2       this.name = name
 3       this.colors = ["red","blue"]
 4     }
 5     SuberType.prototype.sayName = function () {
 6       alert(this.name)
 7     }
 8     function SubType(name,age) {
 9       //继承属性
10       SuberType.call(this, name)  // 第一次调用SuberType()
11       this.age = age
12     }
13     //继承方法
14     SubType.prototype = new SuberType()  //第二次调用SuberType()
15     SubType.prototype.sayAge = function () {
16       alert(this.age)
17     }
18     var instance1 = new SubType("zhao", 27)
19     instance1.colors.push("black")
20     alert(instance1.colors) // red,blue,black
21     instance1.sayName() // zhao
22     instance1.sayAge()  //27
23 
24     var instance2 = new SubType("w", 28)
25     alert(instance2.colors) // red,blue
26     instance2.sayName() // w
27     instance2.sayAge() // 28

优点:实例有各自的属性,和相同的方法

缺点:会俩次调用超类型的构造函数

 

原型式继承

    借助原型可以基于已有的对象创建新对象,不必因此自定义类型

    

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

上面这个函数的本质是:object()对传入的对象执行了一次浅复制

 1  var person = {
 2       name: 'zhao',
 3       friends: ['zhao1','zhao2','zhao3']
 4     }
 5     var anotherPerson = object(person)
 6     anotherPerson.name = 'ss'
 7     anotherPerson.friends.push('Bob')
 8 
 9     var yetAnotherPerson = object(person)
10     yetAnotherPerson.name = 'rr'
11     yetAnotherPerson.friends.push('Bar')
12     alert(person.friends) //zhao1,zhao2,zhao3,Bob,Bar

ECMAScript5通过新增Object.create()方法规范了原型式继承,这个方法接收俩个参数,一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象

在传入一个参数的情况下,Object.create()和object()一样

 1     var person = {
 2       name: 'zhao',
 3       friends: ['zhao1','zhao2','zhao3']
 4     }
 5     var anotherPerson = Object.create(person)
 6     anotherPerson.name = 'ss'
 7     anotherPerson.friends.push('Bob')
 8 
 9     var yetAnotherPerson = Object.create(person)
10     yetAnotherPerson.name = 'rr'
11     yetAnotherPerson.friends.push('Bar')
12     alert(person.friends) //zhao1,zhao2,zhao3,Bob,Bar

Object.create()的第二个参数会覆盖原型对象上的同名属性

 1     var person = {
 2       name: 'zhao',
 3       friends: ['zhao1','zhao2','zhao3']
 4     }
 5     var anotherPerson = Object.create(person)
 6     anotherPerson.name = 'ss'
 7     anotherPerson.friends.push('Bob')
 8 
 9     var yetAnotherPerson = Object.create(person)
10     yetAnotherPerson.name = 'rr'
11     yetAnotherPerson.friends.push('Bar')
12     alert(person.friends) //zhao1,zhao2,zhao3,Bob,Bar

 

寄生式继承

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

   

 1 <script>
 2      function object(o) {
 3        function F() {}
 4        F.prototype = o
 5        return new F()
 6      }
 7 
 8      function createAnother(original) {
 9        var clone = object(original)  // 通过调用函数创建一个新对象
10        clone.sayHi = function () {  // 以某种方式来增强这个对象
11          alert("hi")
12        }
13        return clone  //返回这个对象
14      }
15      var person = {
16        name: "zhaobao",
17        friends: ["zhaobao1","zhaobao2","zhaobao3"]
18      }
19      var anotherPerson = createAnother(person)
20      anotherPerson.sayHi() // hi
21    </script>

 

寄生组合式继承

    这个主要是为了解决组合继承的缺点

   思路:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

              不必为了指定子类型的原型而调用超类型的构造函数,我们需要的只是超类型原型的一个副本。

               本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

       基本模式

           

1   function inheritPrototype(subType, superType) {
2        var prototype = object(superType) //创建对象
3        prototype.constructor = subType  // 增强对象
4        subType.prototype = prototype  //指定对象
5      }

例子

  

 1 function inheritPrototype(subType, superType) {
 2        var prototype = object(superType) //创建对象
 3        prototype.constructor = subType  // 增强对象
 4        subType.prototype = prototype  //指定对象
 5      }
 6      function SuperType(name) {
 7        this.name = name
 8        this.colors = ["red","blue"]
 9      }
10      SuperType.prototype.sayName = function () {
11        alert(this.name)
12      }
13      function SubType(name,age) {
14        SuperType.call(this,name)
15        this.age = age
16      }
17      inheritPrototype(SubType,SuperType)
18      SuperType.prototype.sayAge = function () {
19        alert(this.age)
20      }

 

 这个例子的高效率提现在它只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的、多余的属性。与此同时,原型链还能保持不变,因此,还能正常使用instanceof和isPrototypeOf()

这是最理想的继承方式

posted @ 2017-07-12 02:02  zhaobao1830  阅读(171)  评论(0编辑  收藏  举报