Prototype 原型继承

Prototype 原型继承


prototype源自法语,软件界的标准翻译为“原型”,代表事物的初始形态,也含有模型和样板的意义。

JavaScript的所有function类型的对象都有一个prototype属性。
这个prototype属性本身又是一个object类型的对象,因此我们也可以给这个prototype对象添加任意的属性和方法。
既然prototype是对象的“原型”,那么由该函数构造出来的对象应该都会具有这个“原型”的特性。
事实上,在构造函数的prototype上定义的所有属性和方法,都是可以通过其构造的对象直接访问和调用的。
也可以这么说, prototype提供了一群同类对象共享属性和方法的机制。

我们先来看看下面的代码:
function Person(name)
{
this.name = name; //设置对象属性,每个对象各自一份属性数据
};

Person.prototype.SayHello = function() //给Person函数的prototype添加SayHello方法。
{
alert("Hello, I'm " + this.name);
}

var BillGates = new Person("Bill Gates"); //创建BillGates对象
var SteveJobs = new Person("Steve Jobs"); //创建SteveJobs对象

BillGates.SayHello(); //通过BillGates对象直接调用到SayHello方法
SteveJobs.SayHello(); //通过SteveJobs对象直接调用到SayHello方法

alert(BillGates.SayHello == SteveJobs.SayHello); //因为两个对象是共享prototype的SayHello,所以显示:true



程序运行的结果表明,构造函数的prototype上定义的方法确实可以通过对象直接调用到,而且代码是共享的。
显然,把方法设置到prototype的写法显得优雅多了,尽管调用形式没有变,但逻辑上却体现了方法与类的关系,相对前面的写法,更容易理解和组织代码。

那么,对于多层次类型的构造函数情况又如何呢?

我们再来看下面的代码:
function Person(name) //基类构造函数
{
this.name = name;
};

Person.prototype.SayHello = function() //给基类构造函数的prototype添加方法
{
alert("Hello, I'm " + this.name);
};

function Employee(name, salary) //子类构造函数
{
Person.call(this, name); //调用基类构造函数
this.salary = salary;
};

Employee.prototype = new Person(); //建一个基类的对象作为子类原型的原型,这里很有意思

Employee.prototype.ShowMeTheMoney = function() //给子类添构造函数的prototype添加方法
{
alert(this.name + " {1}quot; + this.salary);
};

var BillGates = new Person("Bill Gates"); //创建基类Person的BillGates对象
var SteveJobs = new Employee("Steve Jobs", 1234); //创建子类Employee的SteveJobs对象

BillGates.SayHello(); //通过对象直接调用到prototype的方法
SteveJobs.SayHello(); //通过子类对象直接调用基类prototype的方法,关注!
SteveJobs.ShowMeTheMoney(); //通过子类对象直接调用子类prototype的方法

alert(BillGates.SayHello == SteveJobs.SayHello); //显示:true,表明prototype的方法是共享的



这段代码的红色部分,构造了一个基类的对象,并将其设为子类构造函数的prototype,这是很有意思的。
这样做的目的就是为了调用SteveJobs.SayHello(),通过子类对象也可以直接调用基类prototype的方法。为什么可以这样呢?

原来,在JavaScript中,prototype不但能让对象共享自己财富,而且prototype还有寻根问祖的天性,从而使得先辈们的遗产可以代代相传。
当从一个对象那里读取属性或调用方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找;
如果 prototype没有,又会去prototype自己关联的前辈prototype那里寻找,直到找到或追溯过程结束为止。

在JavaScript内部,对象的属性和方法追溯机制是通过所谓的prototype链来实现的。
当用new操作符构造对象时,也会同时将构造函数的 prototype对象指派给新创建的对象,成为该对象内置的原型对象。
对象内置的原型对象应该是对外不可见的,尽管有些浏览器(如Firefox)可以让我们访问这个内置原型对象,但并不建议这样做。
内置的原型对象本身也是对象,也有自己关联的原型对象,这样就形成了所谓的原型链。

在原型链的最末端,就是Object构造函数prototype属性指向的那一个原型对象。
这个原型对象是所有对象的最老祖先,这个老祖宗实现了诸如 toString等所有对象天生就该具有的方法。
其他内置构造函数,如Function, Boolean, String, Date和RegExp等的prototype都是从这个老祖宗传承下来的,
但他们各自又定义了自身的属性和方法,从而他们的子孙就表现出各自宗族的那些特征。

这就是JavaScript特有的“原型继承”。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值