JavaScript的原型对象和原型链

引子

有点意思的是,JavaScript的面向对象设计思想跟其他的面向对象语言(如Java、python)的设计思想有所不同。

JavaScript 虽是面向对象的语言,但JavaScript不使用类,不创建类,也不会通过类来创建对象。所幸这样的局面在Es6出现之后得以改变(看来官方也觉得最初的JavaScript设计有点鸡肋)。而在Es6以前,我们不得不使用原型链来解决JavaScript中的有关面向对象的一系列问题:对象唯一性、抽象性、继承性、多态性。而原型链的最大的作用是解决对象的继承问题。

在JavaScript里,万物皆对象。构造函数(Function)是对象,构造函数的原型对象(Function.prototype)也是对象,对象都具有属性__proto__,__proto__指向构造该对象的构造函数的原型对象,而构造函数都会具有属性prototype,指向自身的原型对象。原型对象都具有属性constructor,其指向该原型对象所关联的构造函数,即构造函数.prototype.constructor==构造函数。要注意的是,__proto__是所有对象都具有的属性,而prototype是只有函数,或者说是构造函数才具有的属性,constructor是只有原型对象才具有的属性。

而什么为构造函数,什么为原型对象,下面我们来逐一唠唠,以便讲清Es6以前是怎样实现继承的。

构造函数

跟其他的面向对象语言不同,JavaScript不是采取new 一个class的方式来生成一个对象,而是new一个function来生成对象,被new的这个function被称为构造函数,而生成的对象被称为构造函数的实例对象。

要注意的是,当一个函数被用作构造函数,其中的this指针既不指向window,也不指向undefined,而是指向创建的实例对象。

如下列例子中,Person是atuo的构造函数,其中atuo是Person的一个实例对象

function Person(name){
    
    
    this.name = name
}
var atuo = new Person("atuo") 

在这里插入图片描述

原型对象

在构造函数中,有一个prototype属性,这个属性指向构造函数的原型对象,也就是说,所谓的原型对象就是prototype对象,而通过该构造函数生成的实例对象都会通过__proto__指向该构造函数的prototype对象。

由于所有的实例对象都会共享同一个构造函数的原型对象,所以一般在原型对象中放置固定不更改的属性值,让所有实例对象继承于它,这种属性又被称为引用属性,所以可以把原型对象理解为是实例对象的共享变量和方法;在构造函数中放置不同实例对象可以根据自己需要动态更改的属性值,这种属性被称为本地属性。当一个实例查找某个属性,在其本地属性查找不到的时候就会到引用属性去查找,即是到构造该实例的构造函数的原型对象去查找。有关这方面的内容,可以戳Javascript继承机制的设计思想

function Person(name){
    
    
    this.name = name
}
Person.prototype.age = 21
var atuo = new Person("atuo")
console.log(atuo.age)

在这里插入图片描述

如上面atuo实例有本地属性name,引用属性age,在查找age时,在其构造函数的属性中查找不到(即是在本地属性中查找不到),就会上溯到其构造函数的原型对象Person.prototype中去查找。

构造函数、原型对象和实例对象之间的关系如图所示
在这里插入图片描述

原型链

综合上述所说的构造函数、原型对象、实例对象之间的关系。那么假如我们让一个构造函数的原型对象等于另一个构造函数的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个构造函数的原型对象的指针__proto__,相应地,如此层层递进,就构成了原型对象之间的链条。原型对象的链条就是顺着__proto__这条链层层递进的。这就是所谓的原型链的基本概念。

以下面代码为例,描绘一下其中的原型链。

function Student(name){
    
    
    this.name = name
}
Student.prototype.hello = function(){
    
    
    alert('Hello, ' + this.name + '!');
};
var xiaoming = new Student("xiaoming")
var xiaohong = new Student("xiaohong")

如下图,黄色标注的线条就是其中的原型链。

在这里插入图片描述

继承

上面我们简述了原型链的相关概念,下面我们利用原型链把两个‘类’实现继承。假如我们有一个Parent和一个Child的构造函数,它们毫不相干。如图所示,它们的原型链是不相重合的

在这里插入图片描述

编写代码,使Child继承于Parent,使得两者原型链重合。

function extend(Child, Parent) {
    
    
	var F = function(){
    
    };
	F.prototype = Parent.prototype;
	Child.prototype = new F();
	Child.prototype.constructor = Child;
	Child.uber = Parent.prototype;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/atuo200/article/details/108245426