浅谈javascript中的原型和继承

How to travel in time? read. How to feel time? Write.

前几天仔细的看了看javascript的原型模式和基于原型的继承, 今天就对其作一个简单的总结作为读书笔记。

什么是原型

说原型之前,我们先来说说函数吧。

function Person() {
}

Person.prototype.name = 'Scofiled';
Person.prototype.age = 29;
Person.prottype.sayName = function() {
 return this.name;
}

var person1 = new Person();
person1.sayName(); // 'Scofield'
alert(person1.age); //29

var person2 = new Person();
person2.sayName(); // 'Scofield'
alert(person2.age); //29

这里定义了一个名为Person的函数,然后在在它的prototype属性上又添加了如上几个属性。 然后创建了Person的两个实例。
这个prototype 是哪里来的呢? 我们每创建一个新函数, 就会自动为该函数创建一个prototype属性,这个属性指向一个对象,这个对象就是原型对象
原型对象是拿来干嘛的?如上面代码显示的,person1person2都是Person的实例, 这两个实例都具有了Person.prototype上定义的属性和方法。简而言之,原型对象的用途就是让某特定类型(如:Person)的所有实例(如:person1person2)能共享一些属性和方法

需要注意的是,这里的name,age和sayName()都是原型对象上的属性和方法,并非实例本身所有。在调用构造函数(Person)创建实例(person1person2)后,实例内部将包含一个指针指向构造函数的原型对象(Person.prototype)。 举个列子,读取person1.ageperson1本身是没有age这个属性的, 但是程序会在读取属性时执行一次搜索,从实例本身开始,找到目标则停止,否则继续向上查找原型对象。所以person1.age的值其实是在查找原型对象时返回的。

原型链和继承

说完原型,就来说继承。 继承的实现主要是通过原型链。 上面大概理了一下原型和实例的关系, person1的指针是指向原型对象Person.prototype的,Person.prototype是在定义Person时自动创建并有我们手动添加了一些属性和方法。试想一下,如果Person.prototype指向的是另一个类型的实例会怎样。

function superPerson() {
  this.superProperty = 'super';
}

SuperPerson.prototype.superName = 'protoSuper';
SuperPerson.prototype.getSuperName = function() {
  return this.superName;
}

function Person() {
  this.personProperty = 'person';
}

Person.prototype = new SuperPerson(); // {superProperty: 'super'}

var person1 = new Person(); // {personProperty: 'person'}

person1.getSuperName(); // 'protoSuper'
alert(person1.superProperty); // 'super'
alert(person1.personProperty); // 'person'

如上,定义了一个SuperPerson类型。在定义Person后我们首先创建一个SuperPerson实例并将其赋值给Person.prototype。上面讲原型时提到过,在调用构造函数创建实例后,实例内部将包含一个指针指向构造函数的原型对象,所以这里 new SuperPerson() 得到的实例对象内部也包含一个指针指向SuperPerson的原型对象(即SuperPerson.prototype),当然也会继承SuperPerson.prototype上包含的属性和方法。

在读取 person1.getSuperName 方法时执行了3次搜索,第1次person1本身,没有找到目标; 第2次便根据person1内部指针指向的原型对象(Person.prototype)去查找,也没有找到;第3次根据Person.prototype内部指针指向的原型(SuperPerson.prototype)查找,找到目标。

在读取 person1.superProperty时执行了两次查找,第1次仍然是没有找到,第2次查找Person.prototype时,由于Person.prototypeSuperPerson的一个实例,所以Person.prototype是具有superProperty属性的。所以成功在Person的原型对象上找到。

同样的person1Person的实例,所以person1本身是具有personProperty这个属性的。所以读取person1.personProperty时只执行了一次搜索。

如上面这种一个原型又是另一个类型的实例,这样层层递进,就构成了实力与原型的链条,就是作为的原型链。仿造着这种方法,我们还可以根据需要给这条原型链的头尾继续增加其他类型,来实现属性和方法的继承。

这里只是简单的说了说原型和继承的概念,其中当然还涉及了更为复杂的问题,还是留着下一次再细说吧。