Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

原型链继承图解 #1

Open
vortesnail opened this issue Sep 13, 2019 · 0 comments
Open

原型链继承图解 #1

vortesnail opened this issue Sep 13, 2019 · 0 comments

Comments

@vortesnail
Copy link
Owner

vortesnail commented Sep 13, 2019

原型链继承详解

前言

在大多数面向对象编程语言中,继承是基于类来实现的,但是在JavaScript中是基于原型链来实现的,何为原型链,今天我们一步一步来解析它。

两个函数对象,父类型和子类型

我们首先来创建两个函数对象,并且希望子类型能继承父类型的某些方法,代码如下,很简单:

<script>
  //父类型
function Supper() {
  this.supProp = "Supper Property";
}

Supper.prototype.showSupperProperty = function() {
  console.log(this.supProp);
}

//子类型
function Sub() {
  this.subProp = "Sub Property";
}

Sub.prototype.showSubProperty = function() {
  console.log(this.subProp);
}

</script>

这段代码会在内存空间中有如图所示的内存分配:
Untitled1.png

想要实现继承,我们根据 实例的隐式原型对象指向构造函数的显示原型对象 可知,要想要Sub的实例能访问Supper原型对象中的showSupperProperty函数对象,必须有一条原型链能指向上图中地址为0x234Object实例对象,我们先假如有一个Supper的实例对象已经创建,在图中体现如下:
Untitled1 (1).png

好了,我们先不急,先创建一个Sub的实例看看,他在内存中如何指向的,在上述代码之后添加

var sub = new Sub();

有如下内存分配:
Untitled1 (2).png

根据上图来说,我们的Sub的实例sub并没有与Object构成原型链,无法访问到Supper原型中的showSupperProperty方法,那我们到底该怎么呢? 

首先我们要清楚一点,sub.__proto__的值是怎么来的,Sub函数对象在定义时就已经有了Sub.prototype,而sub.__proto__是由Sub.prototype传递地址值给它而得到的值。我们要让sub._ ``_proto__`` === (Supper的某一个实例对象)不可以构成原型链了吗,需要下面关键的一句话:

Sub.prototype = new Supper();

这句话需要在子类型创建之后立马写上,为什么?你看之后画的图就知道了。
现在内存图如下:
Untitled1 (3).png

由图已经可得到,有一条完整的原型链,故现在子类型的实例对象可以访问父类型的原型中的方法了。
若我们的

Sub.prototype.showSubProperty = function() {
  console.log(this.subProp);
}

不在Sub.prototype = new Supper();之后,那就等于白白丢掉了。。因为原来所指向的Object对象已经成为了垃圾对象。所以,完整的代码如下:

  <script>
    //父类型
    function Supper() {
      this.supProp = "Supper Property";
    }

    Supper.prototype.showSupperProperty = function() {
      console.log(this.supProp);
    }

    //子类型
    function Sub() {
      this.subProp = "Sub Property";
    }

    //子类型的原型为父类型的一个实例对象
    Sub.prototype = new Supper();
		//让子类型的原型的constructor指向子类型
		Sub.prototype.constructor = Sub;

    Sub.prototype.showSubProperty = function() {
      console.log(this.subProp);
    }

    var sub = new Sub();
    sub.showSupperProperty();
    sub.showSubProperty();

  </script>

得到完整图如下:
Untitled1 (4).png

控制台输出验证了其正确性:

屏幕快照 2019-06-18 21.36.52.png

结语:这就是原型链继承了,图还是要多画多看几遍的,好好理解一下很有帮助。

下面简单给一个组合继承的代码,算是模板代码了,本身是借用构造函数继承(应该不能叫真正意义上的继承)和原型链继承的组合,重点是原型链继承,以上已经详细讲述:

  <script>
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }

    Person.prototype.setName = function(name) {
      this.name = name;
    }

    function Student(name, age, price) {
      Person.call(this, name, age); //为了得到属性
      this.price = price;
    }

    Student.prototype = new Person();//为了能看到父类型的方法
    Student.prototype.constructor = Student;//修正constructor属性

    Student.prototype.setPrice = function(price) {
      this.price = price;
    }

    var stu1 = new Student('Bob', 18, 16000);
    stu1.setName('Jack');
    stu1.setPrice(20000);
    console.log(stu1.name, stu1.age, stu1.price);

  </script>
@vortesnail vortesnail added documentation Improvements or additions to documentation JavaScript and removed documentation Improvements or additions to documentation labels Sep 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant