`
siashuayongsheng
  • 浏览: 118278 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

Javascript Prototype

阅读更多
JavaScript通过一种链接机制来支持继承,而不是通过完全面向对象语言(如Java)所支持的基于类的继承模型。每个JavaScript对象都有一个内置的属性,名为prototype。prototype属性保存着对另一个JavaScript对象的引用,这个对象作为当前对象的父对象。

  当通过点记法引用对象的一个函数或属性时,倘若对象上没有这个函数或属性,此时就会使用对象的prototype属性。当出现这种情况时,将检查对象prototype属性所引用的对象,查看是否有所请求的属性或函数。如果prototype属性引用的对象也没有所需的函数或属性,则会进一步检查这个对象(prototype属性引用的对象)的prototype属性,依次沿着链向上查找,直到找到所请求的函数或属性,或者到达链尾,如果已经到达链尾还没有找到,则返回undefined。从这个意义上讲,这种继承结构更应是一种“has a”关系,而不是“is a”关系。

  如果你习惯于基于类的继承机制,那么可能要花一些时间来熟悉这种prototype机制。prototype机制是动态的,可以根据需要在运行时配置,而无需重新编译。你可以只在需要时才向对象增加属性和函数,而且能动态地把单独的函数合并在一起,来创建动态、全能的对象。对prototype机制的这种高度动态性可谓褒贬不一,因为这种机制学习和应用起来很不容易,但是一旦正确地加以应用,这种机制则相当强大而且非常健壮。

这种动态性与基于类的继承机制中的多态概念异曲同工。两个对象可以有相同的属性和函数,但是函数方法(实现)可以完全不同,而且属性可以支持完全不同的数据类型。这种多态性使得JavaScript对象能够由其他脚本和函数以统一的方式处理。



下面是一个例子,其中,BaiduBlog类继承自Blog类。代码如下所示:

<script language="JavaScript" type="text/javascript">
function Blog(){
   var loginName = "anonymous"; // 私有成员,使用var声明
   var pwdProtectedEmail = "anonymous@website.com"; // 私有成员,使用var声明
   // 下面定义的是访问私有成员的公有方法
   this.setLoginName = function(aLoginName){
    loginName = aLoginName;
   }
   this.setPwdProtectedEmail = function(aPwdProtectedEmail){
    pwdProtectedEmail = aPwdProtectedEmail;
   }
   this.getLoginName = function(){
    return loginName;
   }
   this.getPwdProtectedEmail = function(){
    return pwdProtectedEmail;
   }
}
Blog.prototype.provider = "";
Blog.prototype.providerWebsite = "";
Blog.prototype.copyRight = "";
Blog.prototype.displayName = "";
Blog.prototype.blogName = "";
Blog.prototype.description = "";
Blog.prototype.url = "http://";
Blog.prototype.newBlog = function(){
   return new Blog();
};
Blog.prototype.generateBlogURL = function(){};
Blog.prototype.getGreetins = function(){
   var words = "欢迎使用" + this.provider + "提供的博客服务,谢谢!<BR>";
   return words;
};
Blog.BELONGS_COUNTRY = "中国"; // 常量
Blog.WEB_RULES = "WEB 2.0";


function BaiduBlog(){
   BaiduBlog.prototype.constructor(); // 调用基类的构造函数
};
BaiduBlog.prototype = new Blog(); // 绑定
BaiduBlog.prototype.provider = "百度";
BaiduBlog.prototype.providerWebsite = "www.baidu.com";
BaiduBlog.prototype.copyRight = "2008<B> 百度 </B>版权归百度所有";
BaiduBlog.prototype.getBaiduSearcherInYourBlog = function(displayName){
   var searcherURL = "你可以直接使用下面的链接进行站内检索:<BR>";
   searcherURL += "http://hi.baidu.com/sys/search?type=0&sort=1&entry=1&region=2&hi=";
   searcherURL += displayName;
   searcherURL += "&word=";
   return searcherURL;
};
BaiduBlog.prototype.generateBlogURL = function(){   // 生成用户博客的地址URL
   var url = "http://hi.baidu.com/";
   url += this.displayName; // 访问继承自基类Blog而来的displayName
   return url;
};
BaiduBlog.prototype.getGreetins = function(){   // 该方法重写了基类Blog中的getGreetins()方法
   var words = Blog.prototype.getGreetins.call(this); // 调用基类中被重写的该方法getGreetins
   words += "如果您在使用 " + this.provider + "博客!如果您在使用过程中遇到问题,请联系管理员。<BR>";
   words += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
   words += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
   words += "百度管理员Email : admin@baidu.com";
   return words;
};


var myBaiduBlog = new BaiduBlog();
myBaiduBlog.displayName = "shirdrn";
myBaiduBlog.setLoginName("s2008xyk");
myBaiduBlog.blogName = "异域王者";
myBaiduBlog.description = "虽体解吾犹未变兮,岂余心之可惩。";
myBaiduBlog.setPwdProtectedEmail("shirdrn@protected.com");


var belongsArea = Blog.BELONGS_COUNTRY;
var blogRules = Blog.WEB_RULES;
var provider = myBaiduBlog.provider;
var providerWebsite = myBaiduBlog.providerWebsite;
var greetins = myBaiduBlog.getGreetins("百度");
var copyRight = myBaiduBlog.copyRight;
var logName = myBaiduBlog.getLoginName();
var pwdProtectedEmail = myBaiduBlog.getPwdProtectedEmail();
var blogName = myBaiduBlog.blogName;
var description = myBaiduBlog.description;
var url = myBaiduBlog.generateBlogURL();
var searcher = myBaiduBlog.getBaiduSearcherInYourBlog("shirdrn");

document.write("<B>所在地区 : </B>" + belongsArea + "<BR>");
document.write("<B>博客规范 : </B>" + blogRules + "<BR>");
document.write("<B>供应商名 : </B>" + provider + "<BR>");
document.write("<B>供应商网 : </B>" + providerWebsite + "<BR>");
document.write("<B>博客问候 : </B>" + greetins + "<BR>");
document.write("<B>博客版权 : </B>" + copyRight + "<BR>");
document.write("<B>登录帐户 : </B>" + logName + "<BR>");
document.write("<B>保护邮箱 : </B>" + pwdProtectedEmail + "<BR>");
document.write("<B>博客名称 : </B>" + blogName + "<BR>");
document.write("<B>博客描述 : </B>" + description + "<BR>");
document.write("<B>博客链接 : </B>" + url + "<BR>");
document.write("<B>我的搜索 : </B>" + searcher + "<BR>");

</script>

运行结果如下所示:

所在地区 : 中国
博客规范 : WEB 2.0
供应商名 : 百度
供应商网 : www.baidu.com
博客问候 : 欢迎使用百度提供的博客服务,谢谢!
如果您在使用 百度博客!如果您在使用过程中遇到问题,请联系管理员。
                         百度管理员Email : admin@baidu.com
博客版权 : 2008 百度 版权归百度所有
登录帐户 : s2008xyk
保护邮箱 : shirdrn@protected.com
博客名称 : 异域王者
博客描述 : 虽体解吾犹未变兮,岂余心之可惩。
博客链接 : http://hi.baidu.com/shirdrn
我的搜索 : 你可以直接使用下面的链接进行站内检索:
http://hi.baidu.com/sys/search?type=0&sort=1&entry=1®ion=2&hi=shirdrn&word=


对JavaScript实现继承,借助上面代码进行说明和总结一下:

1、在一个类中设定其成员为私有,使用var声明。只要在类的构造函数中使用var声明了成员变量,那么就不可以通过该函数对象的对象实例来直接访问该私有成员(不能使用对象实例名加上“.”加上该私有成员变量名来访问),想要访问它,必须构造一个共有的方法来提供访问接口,例如上面程序中,loginName 被使用var声明了,即为私有成员,只能通过编写的“Setter/Getter”和来设置或者读取它的数据,如下Blog类定义所示:

function Blog(){
   var loginName = "anonymous"; // 私有成员,使用var声明
   var pwdProtectedEmail = "anonymous@website.com"; // 私有成员,使用var声明
   // 下面定义的是访问私有成员的公有方法
   this.setLoginName = function(aLoginName){
    loginName = aLoginName;
   }
   this.setPwdProtectedEmail = function(aPwdProtectedEmail){
    pwdProtectedEmail = aPwdProtectedEmail;
   }
   this.getLoginName = function(){
    return loginName;
   }
   this.getPwdProtectedEmail = function(){
    return pwdProtectedEmail;
   }
}

2、子类继承基类的一般格式如下:

function BaseClass(){} // 基类的定义

……

function SubClass(){
   BaseClass.prototype.constructor();   // 调用基类的构造函数,这里使用prototype对象的构造方法constructor()
};
BaiduBlog.prototype = new Blog(); // 进行绑定,使子类SubClass继承自基类BaseClass


3、子类继承自基类,基类的成员变量具有默认值,子类在构造对象实例的时候,必须修改对应属性的值,否则子类对象实例的属性值是基类的属性的默认值。

子类继承自基类,那么子类也继承了基类的成员变量和成员方法,除了私有成员以外,可以直接通过this关键字来访问。

4、对于子类重写了基类的成员方法,那么子类的对象实例在需要访问基类的该成员方法时,可以通过下面的方式来实现:

function BaseClass(){} // 基类的定义
BaseClass.prototype.someMethod(){
   do what BaseClass's instance should do;
}


function SubClass(){
   BaseClass.prototype.constructor();   // 调用基类的构造函数,这里使用prototype对象的构造方法constructor()
}
SubClass.prototype.callMethod(){
  BaseClass.prototype.someMethodc.call(this);
   do what SubClass's instance should do;
}

因为基类是最高层的抽象,基类中某些高级的抽象同样适合子类,而子类又具有自己的某些特征,所以子类在重写基类的成员方法的时候,可以先调用基类的该同名成员方法,然后在添加自己特有的动作或者特征。

通过上面,在子类的someMethodc()成员方法中执行BaseClass.prototype.someMethodc.call(this);这句,就可以获取到基类的对象实例执行该方法所得到的数据,然后子类又执行了一系列子类对象实例应该执行的操作:do what SubClass's instance should do;。

5、在类的构造函数之外使用prototype定义类的成员,都是共有的,可以直接使用“.”运算符来访问。在类的构造函数体之内,使用this.来指定的成员就是共有的成员。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics