javascript中6中继承方式

1. 原型链继承

先回顾一下构造函数,原型和实例的关系:每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象

的内部指针。如果我们让原型对象等于另一个类型的实例,就形成了一条原型链。

    function SuperType() {
        this.name = ‘SuperType‘
    }
    SuperType.prototype.sayNmae = function () {
        console.log(this.name)
    }
    function SubType() {
        this.remark = ‘SubType‘
    }
    SubType.prototype = new SuperType()
    SubType.prototype.sayRemark = function () {
        console.log(this.remark)
    }
    var instance1 = new SubType()
    console.log(instance1 instanceof SubType)     //true
    console.log(instance1 instanceof SuperType)     //true
    console.log(instance1 instanceof Object)        //true

讲再多都没有一张图来的明白   顺着__proto__就是我们说的原型链啦。另外超类型是指SuperType,子类型是指Subtype

原型链的问题

    function SuperType() {
        this.colors = [‘red‘,‘yellow‘,‘blue‘]
    }
    function SubType() {
    }
    SubType.prototype = new SuperType()
    var instance1 = new SubType()
    var instance2 = new SubType()

    instance1.colors.push(‘green‘)
    console.log(instance1.colors)//["red", "yellow", "blue", "green"]
    console.log(instance2.colors)//["red", "yellow", "blue", "green"]

包含引用类型值的原型属性会被所有实例共享,这里在超类型中定义的colors原本是每个实例单独所有的,但是由于把SuperType的实例作为了SubType的prototype,

colors也就成了所有SubType实例所共享的了,所以修改一个实例colors,其他的实例也会改变

原型链的另一个问题就是创建自类型实例时,无法向超类型的构造函数中传值

2.借用构造函数

    function SuperType(name) {
        this.name = name
        this.colors = [‘red‘,‘blue‘,‘green‘]
    }
    function SubType() {
        SuperType.apply(this,arguments) // 在子类型内部调用超类型
    }
    var instance1 = new SubType(‘Alan‘)
    var instance2 = new SubType(‘Bob‘)
    instance1.colors.push(‘black‘)
    console.log(instance1.colors)       //["red", "blue", "green", "black"]
    console.log(instance2.colors)       //["red", "blue", "green"]
    console.log(instance1.name)         //Alan
    console.log(instance2.name)         //Bob

借用构造函数最重要的一步在于,在子类型内部调用超类型的构造函数,修改了this指向,同时满足了参数的传递

借用构造函数的问题

方法都在构造函数中定义,无法实现函数复用

3.组合继承

组合继承又叫经典继承,解决了原型链和借用构造函数的问题。

 

    function SuperType(name,age) {
        this.name = name
        this.age = age
        this.colors = [‘red‘,‘blue‘,‘green‘]
    }
    Object.defineProperties(SuperType.prototype,{
        sayName:{
            value:function () {
                console.log(this.name)
            },
            writable:true,
            configurable:true,
            enumerable:true
        }
    })
    function SubType() {
        SuperType.apply(this,arguments)     //第二次调用超类型构造函数
    }
    SubType.prototype = new SuperType()   //第一次调用超类型构造函数
    var instance1 = new SubType(‘Banks‘,22)
    var instance2 = new SubType(‘Bob‘,33)
    instance1.colors.push(‘black‘)
    console.log(instance1.colors) //["red", "blue", "green", "black"]
    console.log(instance2.colors) //["red", "blue", "green"]

组合继承,在构造函数中定义非公用属性,在原型中定义公用方法。

组合继承的问题

如果说这种继承方式还有问题的话,那就是调用了两次超类型构造函数。

4.原型式继承

道格拉斯,克罗克福德(没错,就是那个提出稳妥对象的小伙伴)提出了原型式继承。他的想法是借助已有的对象创建新对象,同时不必因此创建自定义类型。

function object(o) {
        function F() {   //相当于原型链继承中的自类型构造函数
        }
        F.prototype = o   // 这里的o相当于原型链继承中的超类型的实例
        return new F()
    }

在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的新实例

和原型链继承有相似的地方,但是没有超类型构造函数,并且把一系列操作放封装在了object函数内部。从本质上讲,object()对其中的对象

执行了一次潜复制

    var person = {
        name:‘Nicholas‘,
        age:22,
        friends:[‘Shelby‘,‘Court‘,‘Van‘]
    }
    var anotherPerson = object(person)
    anotherPerson.name = ‘Alan‘
    anotherPerson.friends.push(‘Bob‘)
    var yetAnoterPerson = object(person)
    console.log(anotherPerson.name)         //Alan
    console.log(anotherPerson.friends)      //[‘Shelby‘,‘Court‘,‘Van‘,‘Bob‘]
    console.log(yetAnoterPerson.name)       //Nicholas
    console.log(yetAnoterPerson.friends)    //[‘Shelby‘,‘Court‘,‘Van‘,‘Bob‘]

原型式继承要有一个对象作为另一个对象的继承,然后将这个对象传递给object函数,然后根据需求对得到的对象进行修改

但是person对象中包含friends引用类型,这里的friends是共有的,这里在修改(注意是修改,而不是改变)

    anotherPerson.friends = [‘Shelby‘]
    console.log(anotherPerson.friends)      //["Shelby"]
    console.log(yetAnoterPerson.friends)    //[‘Shelby‘,‘Court‘,‘Van‘,‘Bob‘]

上面的代码我们改变了anotherPerson的friends,这里会在anotherPerson实例中添加一个friends属性,并不会改动,person中的friends

原型链继承中也是一样的道理

原型式继承的问题

原型式继承创建的对象,相当于传入对象的副本,和原型链继承的问题一样,每个实例没有自定义的属性。而且原型式继承进行的是浅复制,无法用instanceof操作符检测。

关于instanceof操作符与原型链 参考这一篇

https://www.cnblogs.com/flawlessBlithe/p/8515435.html

5.寄生式继承

寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再返回对象。

function createAnother(original) {
        var clone = object(original)
        clone.sayHi = function () {    // 以某种方式增强对象 返回实例之前给实例添加方法
            console.log(‘hi‘)
        }
        return clone
    }

寄生式继承的问题

寄生式继承解决了原型式继承无法自定义方法的问题,但是依然是进行的浅复制,无法进行instanceof操作符检测

6.寄生组合式继承

看名字大家就想到了,寄生组合式继承为的就是解决,寄生式继承无法进行instanceof操作符检测的问题,以及组合式继承调用了两次超类型构造函数的问题。

function object(o) {
    function F() {   //相当于原型链继承中的子类型构造函数
    }
    F.prototype = o   // 这里的o相当于原型链继承中的超类型的实例
    return new F()
}

function SuperType(name,age) {
    this.name = name
    this.age = age
}
SuperType.prototype.sayName = function () {
    console.log(this.name)
}

function SubType() {
    SuperType.apply(this,arguments)
}
// 下面这个函数做的操作为的是解决组合继承中第二次调用超类型构造函数的问题
// 即这一步 SubType.prototype = new SuperType()
function inheritPrototype(SubType,SuperType) {
    var n = object(SuperType.prototype)   //对超类型的原型进行浅复制
    n.constructor = SubType    // 如果没有这一步后面将无法使用instanceof检查是不是SubType的实例
    /*  上面的操作是使用原型式继承的方式 创造一个SuperType.prototype的副本
        也就是替换 new Supertype() 这一步
     */
   console.log( n.__proto__ === SuperType.prototype )// true
    console.log(n instanceof SuperType)  //true
    SubType.prototype = n
}
inheritPrototype(SubType,SuperType)
SubType.prototype.sayAge = function () {  // 这里在prototype中添加sayAge方法已经是添加在了 inheritPrototype 函数内部的n上
    console.log(this.age)
}
var instance = new SubType(‘Alan‘,23)
console.log(instance instanceof SubType) //true
console.log(instance instanceof SuperType) // true

寄生组合式继承 比较难理解的那里应该是解决第二次调用超类型构造函数的部分。

听说寄生组合式继承还有问题。。。。。 应该是 太麻烦了  哈哈哈

原文地址:https://www.cnblogs.com/flawlessBlithe/p/8524680.html

时间: 2024-10-04 14:23:42

javascript中6中继承方式的相关文章

类设计中几种继承方式

 通过继承能够从已有的类派生出新的类,而派生类继承了基类的特征,包括方法.正如继承一笔财产要比自己白手起家容易一样,通过继承派生出的类通常比设计新类要容易得多.下面是可以通过继承完成的一些工作. ①可以在已有类的基础上添加功能. ②可以给类添加数据. ③可以修改类方法的行为. C++有三种继承方式:公有继承.保护继承和私有继承. 一.公有继承 公有继承是最常用的方式,它建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行. ①公有继承不建立

JavaScript 的几种继承方式

JavaScript 的几种继承方式 原型链继承 构造函数继承 组合继承 (伪经典继承) 原型式继承 寄生式继承 寄生组合式继承 ES6 extends 继承 1, 原型链继承 原理是将父对象的属性和方法通过prototype进行引用 function people() { this.flag = true; this.func = function() { console.log("this is people func"); } } function boy() { this.se

JavaScript常见的六种继承方式

前言 面向对象编程很重要的一个方面,就是对象的继承.A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法.这对于代码的复用是非常有用的. 大部分面向对象的编程语言,都是通过"类"(class)实现对象的继承.传统上,JavaScript 语言的继承不通过 class(ES6 引入了class 语法),而是通过"原型对象"(prototype)实现.那么在JS中常见的继承方式有几种呢? 如需本文源码,请猛戳 常见的六种继承方式 如果觉得文章对你有些许帮助

JavaScript 常见的六种继承方式

JavaScript 常见的六种继承方式

C++中不同的继承方式

[转自e良师益友网]众所周知C语言的强大之处,而C++编程语言功能同样强大,可以对多种程序设计风格提高支持,推荐学习C++编程-基础知识篇.其中就包括面向对象的各种特性. 我们在这里先为大家讲解一下C++继承的一些基本概念:C++继承方式分为两种,普通继承和虚拟继承(virtual).具体的继承又根据父类中的函数是否virtual而不同. 下面就单继承分为几种情况阐述: 方式1.普通继承+父类无virtual函数 若子类没有新定义virtual函数 此时子类的布局是 : 由低地址->高地址 为父

C++中三种继承方式的区别

本文来自https://zhidao.baidu.com/question/159111767.html  详细说明了三种继承方式的区别,好文 还可参考另一篇文章: https://blog.csdn.net/one_super_dreamer/article/details/81611118 https://blog.csdn.net/u011857683/article/details/82120998 public公有继承 protected保护继承 private私有继承 我们知道类的p

C++中的struct与class继承方式

代码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 //class A{ 7 struct A{ 8 public: 9 int i{5}; 10 void print(){ 11 cout<<i<<endl; 12 } 13 }; 14 //class B:A{ 15 struct B:A{ 16 public: 17 }; 18 19 int main(){

C++中的三种继承方式

1,被忽略的细节: 1,冒号( :)表示继承关系,Parent 表示被继承的类,public 的意义是什么? 1 class Parent 2 { 3 4 }; 5 6 class Child : public Parent 7 { 8 9 }; 2,有趣的问题: 1,是否可以将继承语句中的 public 换成 protected 或者 private?如果可以,与 public 继承有什么区别? 3,有趣的尝试编程实验: 1 #include <iostream> 2 #include &l

Javascript之对象的继承

继承是面向对象语言一个非常重要的部分.许多OOP语言都支持接口继承和实现继承两种方式.接口继承:继承方法签名:实现继承:继承实际的方法.在ECMAScript中函数是没有签名的,所以也就无法实现接口继承,只能支持实现继承. 在JavaScript中有大概六种继承方式,它们分别是:原型链继承,借用构造函数继承,组合继承,原型式继承,寄生式继承和寄生组合式继承.下面就是对着六种继承方式的详细介绍. 1.原型链 基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在这里还得补充一下,每个构

Javascript 进阶 面向对象编程 继承的一个例子

Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承,这篇使用一个例子来展示js如何面向对象编程,以及如何基于类实现继承. 1.利用面向对象的写法,实现下面这个功能,实时更新数据的一个例子: 2.使用对上面类的继承,完成下面的效果: 好了,不多说,js的训练全靠敲,所以如果觉得面向对象不是很扎实,可以照着敲一个,如果觉得很扎实了,提供了效果图,可以自己写试试. 1.第一个效果图代码: [javascript] view pl