Open vortesnail opened 5 years ago
在大多数面向对象编程语言中,继承是基于类来实现的,但是在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>
这段代码会在内存空间中有如图所示的内存分配:
想要实现继承,我们根据 实例的隐式原型对象指向构造函数的显示原型对象 可知,要想要Sub的实例能访问Supper原型对象中的showSupperProperty函数对象,必须有一条原型链能指向上图中地址为0x234的Object实例对象,我们先假如有一个Supper的实例对象已经创建,在图中体现如下:
Sub
Supper
showSupperProperty
0x234
Object
好了,我们先不急,先创建一个Sub的实例看看,他在内存中如何指向的,在上述代码之后添加
var sub = new Sub();
有如下内存分配:
根据上图来说,我们的Sub的实例sub并没有与Object构成原型链,无法访问到Supper原型中的showSupperProperty方法,那我们到底该怎么呢?
sub
首先我们要清楚一点,sub.__proto__的值是怎么来的,Sub函数对象在定义时就已经有了Sub.prototype,而sub.__proto__是由Sub.prototype传递地址值给它而得到的值。我们要让sub._ ``_proto__`` === (Supper的某一个实例对象)不可以构成原型链了吗,需要下面关键的一句话:
sub.__proto__
Sub.prototype
sub._ ``_proto__`` === (Supper的某一个实例对象)
Sub.prototype = new Supper();
这句话需要在子类型创建之后立马写上,为什么?你看之后画的图就知道了。 现在内存图如下:
由图已经可得到,有一条完整的原型链,故现在子类型的实例对象可以访问父类型的原型中的方法了。 若我们的
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>
得到完整图如下:
控制台输出验证了其正确性:
结语:这就是原型链继承了,图还是要多画多看几遍的,好好理解一下很有帮助。
下面简单给一个组合继承的代码,算是模板代码了,本身是借用构造函数继承(应该不能叫真正意义上的继承)和原型链继承的组合,重点是原型链继承,以上已经详细讲述:
<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>
原型链继承详解
前言
在大多数面向对象编程语言中,继承是基于类来实现的,但是在JavaScript中是基于原型链来实现的,何为原型链,今天我们一步一步来解析它。
两个函数对象,父类型和子类型
我们首先来创建两个函数对象,并且希望子类型能继承父类型的某些方法,代码如下,很简单:
这段代码会在内存空间中有如图所示的内存分配:
想要实现继承,我们根据 实例的隐式原型对象指向构造函数的显示原型对象 可知,要想要
Sub
的实例能访问Supper
原型对象中的showSupperProperty
函数对象,必须有一条原型链能指向上图中地址为0x234
的Object
实例对象,我们先假如有一个Supper
的实例对象已经创建,在图中体现如下:好了,我们先不急,先创建一个
Sub
的实例看看,他在内存中如何指向的,在上述代码之后添加有如下内存分配:
根据上图来说,我们的
Sub
的实例sub
并没有与Object
构成原型链,无法访问到Supper
原型中的showSupperProperty
方法,那我们到底该怎么呢?首先我们要清楚一点,
sub.__proto__
的值是怎么来的,Sub
函数对象在定义时就已经有了Sub.prototype
,而sub.__proto__
是由Sub.prototype
传递地址值给它而得到的值。我们要让sub._ ``_proto__`` === (Supper的某一个实例对象)
不可以构成原型链了吗,需要下面关键的一句话:这句话需要在子类型创建之后立马写上,为什么?你看之后画的图就知道了。 现在内存图如下:
由图已经可得到,有一条完整的原型链,故现在子类型的实例对象可以访问父类型的原型中的方法了。 若我们的
不在
Sub.prototype = new Supper();
之后,那就等于白白丢掉了。。因为原来所指向的Object对象已经成为了垃圾对象。所以,完整的代码如下:得到完整图如下:
控制台输出验证了其正确性:
结语:这就是原型链继承了,图还是要多画多看几遍的,好好理解一下很有帮助。
下面简单给一个组合继承的代码,算是模板代码了,本身是借用构造函数继承(应该不能叫真正意义上的继承)和原型链继承的组合,重点是原型链继承,以上已经详细讲述: