zoukankan      html  css  js  c++  java
  • 深入理解JavaScript中的继承

    1前言

    继承是JavaScript中的重要概念,可以说要学好JavaScript,必须搞清楚JavaScript中的继承。我最开始是通过看视频听培训班的老师讲解的JavaScript中的继承,当时看的时候好像是理解了,可是没过多久就忘了,说明当时学的时候只是死记硬背,而没有深入理解,所以容易遗忘。因此,我认为,一个知识点,如果是真的弄明白了其中的原理,是不需要强行记忆的,真正理解之后会有一种融会贯通的感觉,自然而然就存在于脑海中了。废话不多说了,今天我是在看了《JavaScript高级程序设计》之后,才感觉真正理解了JavaScript中的继承,故而写下这篇博客记录一下。

    2原型链

      原型链是实现继承的主要方法。那么何为原型链呢?要回答这个问题,首先要从构造函数、原型对象和实例对象三者的关系讲起。实例对象是由构造函数创建的,构造函数中有一个prototype属性,可以看成一个指针,它指向原型对象,实例对象中有一个_proto_属性,它的指针也指向原型对象,而原型对象中有一个constructor属性,它指向的是构造函数,这样就形成了如下图所示的一个关系图(图是直接用的别人的,这个图没有把constructor画出来)。

      接下来,重点来了,如果我们让原型对象等于另一个类型的实例,那么此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念。

    3继承

    3.1通过原型链继承

      首先,如何通过原型链继承?请看以下代码:

    function SuperType() {
    this.property = true;
    }
    SuperType.prototype.getSuperValue = function () {
    return this.property;
    }
    function SubType() {
    this.subproperty = false;
    }
    SubType.prototype = new SuperType();//这里就是让子类型的原型对象等于超类型的实例,从而继承了超类型SuperType
    SubType.prototype.getSubValue = function () {
    return this.subproperty;
    }
    var instance = new Subtype();
    alert(instance.getSuperValue());//true

      实现继承的本质是重写原型对象,代之以一个新类型的实例。

      那么,通过原型链实现继承有什么缺点?第一个问题,来自包含引用类型值的原型。包含引用类型值的原型属性会被所有实例共享,一旦在一个实例中修改了属性值,其他任何实例中的该属性值也随之改变了,也就是实例对象就无法拥有自身的私有属性了。第二个问题,在创建子类型的实例时,不能向超类型的构造函数中传递参数。

    3.2借用构造函数继承

      为了解决原型链继承中存在的一些问题,借用构造函数实现继承的方法就产生了,请看以下代码:

    function SuperType(name) {
    this.name = name;
    }
    function SubType() {
    SuperType.call(this,"smalldy");
    this.age = 24;
    }
    var instance = new SuperType();
    alert(instance.name);//"smalldy"
    alert(instance.age);//24

      借用构造函数实现继承也有缺点,也就是在超类型的原型中定义的方法,对子类型而言是 不可见的,结果所有方法都在构造函数中定义,无法实现函数复用。

    3.3组合继承

      组合继承的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承,请看以下代码:

    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;
    }
    SubType.prototype = new SuperType();
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function () {
    alert(this.age);
    };
    var instance1 = new SubType("smalldy",24);
    instance1.colors.push("black");
    alert(instance1.colors);
    instance1.sayName();
    instance1.sayAge();
    var instance2 = new SubType("youcaihua",25);
    alert(instance2.colors);
    instance2.sayName();
    instance2.sayAge();

      组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点。

    3.4原型式继承

      思路:基于已有的对象创建新对象。

    function object(o) {
    function F() {
    }
    F.prototype = o;
    return new F();
    }

      将一个对象作为另一个对象的基础,把它传递给object()函数,然后再根据具体需求对得到的对象加以修改即可。

    3.5寄生式继承

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

    function createAnother(original) {
    var clone = object(original);
    clone.sayHi = function () {
    alert("hi")
    };
    return clone;
    }

    3.6寄生组合式继承

      组合继承最大的问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

      所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

    function inheritPrototype(subType,superType) {
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
    }

      函数接收两个参数:子类型构造函数和超类型构造函数。在函数内部,第一步是创建超类型原型的一个副本。第二步是为创建的副本添加constructor属性,从而弥补因重写原型而失去的默认的constructor属性。最后一步,将新创建的对象赋值给子类型的原型。

      寄生组合式继承是引用类型最理想的继承范式。

  • 相关阅读:
    GridView分页用法
    鼠标移动 改变Datagrid行的背景颜色
    asp.net清空某一类控件或置某一状态
    解决XP系统下"HTTP 错误 403.9 禁止访问:连接的用户过多"的问题
    Asp.net项目路径获取方法
    误删资料恢复 技巧(转载)
    linux命令
    破解win2003“终端服务器授权”激活许可证! (转载)
    apache搭建网站更改默认语言为GB2312
    jquery实现图片广告轮换效果
  • 原文地址:https://www.cnblogs.com/smalldy/p/10846835.html
Copyright © 2011-2022 走看看