美文网首页
继承的方法

继承的方法

作者: 以手画圆心 | 来源:发表于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)
}

相关文章

  • 原型相关(二)

    1.继承 继承方式:接口继承(只继承方法签名)实现继承(继承实际的方法)ECMAScript只支持实现继承,并且主...

  • 我碰到的前端面试题(js)

    1.js实现继承有哪几种方法? 方法一:原型链继承 方法二: 构造函数继承 方法三: 组合继承 2.this指向问...

  • 继承

    一. 单继承 继承的概念一般子女继承父辈 2.多继承 3.重写、调用父类方法 二. 静态方法和类方法 1、类方法 ...

  • 面向对象——继承

    许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。ECMAS...

  • 7、面向对象的程序设计3(《JS高级》笔记)

    三、继承 许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际方法。由...

  • 高程三 关于原型链 阅读笔记

    许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。由于函数没...

  • javaScript继承

    很多面向对象语言都支持两种继承:接口继承和实现继承,前者继承方法签名,后者继承实际的方法。接口继承在 ECMAS...

  • js面向对象设计---继承

    许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。如前所述,...

  • 原型与继承

    什么是继承? 继承父级的属性和方法和共享(原型链)的属性和方法 组合继承 通过原型链继承共享的方法和属性;通过构造...

  • 面向对象的继承

    面向对象继承问题:属性继承:构造函数伪装方法继承:原型链 我们先写一个简单的对象 实现属性的继承 实现方法的继承 ...

网友评论

      本文标题:继承的方法

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