JavaScript面向对象编程知识点

JavaScript面向对象编程知识点

首先我们简单定义一个OO中关于继承定义的子集(不完整定义)
 
继承 : 子类拥有其父类的方法和属性, 子类可以重新定义从其父类继承而来的方法
 
在C++ Class中的继承通过以下简洁方式表现
class CParent //父类
{
public :
string str;
//属性
virtual void foo(){}
//方法
};
class CChild :public CParent
//子类,继承
{
public:
virtaul void foo(){ //函数覆盖
CParent::foo();//调用父类的方法,不过在父类的方法中的this却是子类实例的指针哦
}
}
 
在JScript中要实现继承要繁琐得多,要使用prototype 这些东东。那么我们在JScript中有没有简单的方法可以模拟这种效果?经过一番尝试,我想出了一个还算简洁的解决方案,没考虑效率和实用性,给大家参考一下而已。
先说一下使用方法:
 
<!--模拟继承效果的脚本库-->
<SCRIPT LANGUAGE="jscript" src="oop.htm"></SCRIPT>
<SCRIPT LANGUAGE="javascript">
<!--
function Parent()
{
Class(this);
//使这个类从我们的最顶层的基类派生而来,类似于MFC中的类都从CObject派生呵呵,必须是第一条语句
this.str="Class Parent 的属性值";
this.OutStr=function() { window.alert("Class Parent 的方法/t"+this.str); }
}
function Son()
{
Class(this);
//同上,一定要有
this.Inherit(Parent);
//继承Parent
this.OutStr=function() {
//重写Parent的OutStr方法
window.alert("Class Son 的方法/t"+this.str);
}
this.OutStr2=function(){
this.OutStr();//调用Son的OutStr
this.Parent_OutStr();//调用父类Parent的OutStr方法
}
}
function Grandson()
{
Class(this);//同上
this.Inherit(Son);//继承Son
this.str="Class Grandson的属性值";
}
var b=new Son();
var c=new Grandson();
b.OutStr();//输出“Class Son的方法 Class Parent 的属性值“,因为Son重写了Paren的OutStr方法但没改变str属性值
c.OutStr();//输出“Class Son的方法 Class Grandson的属性值“,因为Grandson没有重写Son的OutStr方法但改变了str属性值
b.Parent_OutStr(1,"str",window);//调用Parent的OutStr,输出“Class Parent的方法 Class Parent 的属性值“,因为Son没改变str属性值
c.Son_OutStr();//调用Son的OutStr,输出“Class Son的方法 Class Grandson的属性值“,因为Grandson改变了str属性值
c.Son_Parent_OutStr();//调用Parent的OutStr,输出“Class Parent的方法 Class Grandson的属性值“,因为Grandson改变了str属性值
b.OutStr2();
window.alert(c.Tree());//显示c的继承关系图
window.alert(c.MembersMap());//显示c的方法和属性
//-->
</SCRIPT>

下面把oop.htm的源代码贴出来大家有兴趣参考一下:)
 
//这是个脚本文件,请用&lt;SCRIPT LANGUAGE=jscript src="oop.htm"&gt;&lt;/SCRIPT&gt;的方式使用
//<SCRIPT LANGUAGE=javascript>
/////////////common function///////////////////////
//取得函数对象的名称,返回字符串

function FunctionName(f)
{
if(typeof(f)=="function"){
var pn=new String(f);
var n=pn.indexOf("(",0);
pn=pn.substring(0,n);
pn=pn.replace(/^[ /f/v/t/b/n/r]*/g,"");
pn=pn.replace(/^function/g,"");
pn=pn.replace(/^[ /f/v/t/b/n/r]*/g,"");
pn=pn.replace(/[ /f/v/t/b/n/r]*$/g,"");
return pn;
}
return "";
}

///////////////////////////////////////////////////////
//基类

function JSClass()
{

//取得类名,返回字符串
this.ClassName=function() { return FunctionName(this.constructor); }

//指定继承_base类,可以带基类初始化参数如this.Inherit(classBase,param1,param2,param3);
//返回true或false

this.Inherit=function(_base)
{

//检验_base是合法类而且尚未继承_base类
if(typeof(_base)=="function" && !this.IsMyParent(_base))
{

//如此函数是在顶层实例构造(即直接用new产生实例)时调用,isRoot为true
//如此函数是在嵌套派生(即在Inherit中调用基类)时嵌套调用,isRoot为false

var isRoot=(this.constructor==this.Inherit.caller);

this.___super=_base;

//带参数初始化基类
var callString="";
for(i=1;i<arguments.length;i++){
if(i>1) callString+=",";
callString+="arguments["+i+"]";
}
eval("this.___super("+ callString +");");
this.___super=null;
 
if(isRoot)//如果是顶层实例
{

//{{{如不需要调用IsMyParent和调用基类的方法及工具函数可去掉以下代码
eval("this.___super=new _base(" + callString + ");");//生成基类的实例
Class(this.___super);//保证基类是JSClass的派生类
var pn=this.___super.ClassName();
for(key in this.___super){
if((!this.IsKeyWord(key)) && typeof(this.___super[key])=="function"){
//不要前面带"___"的函数和保留函数
eval("this."+ pn + "_" + key + "=this.___super[/"" + key + "/"]");//保存基类方法使之可用this.基类名_基类方法的方式使用
}
}
var pr=this.Parents();
pr[pn]=this.___super.Parents();//将基类的派生关系数组添加到本类的派生关系数组中
pr.length++;
this.___super=null;
//}}}
}
return true;
}
return false;
}
//toolMethod

//判断是否是自己的直接父类,返回true或false
this.IsMyParent=function(obj)
{
var objn="";
var ps=this.Parents();
if(isClass(obj)) objn=obj.ClassName();
else if(typeof(obj)=="function") objn=FunctionName(obj);

if(objn!="") return (typeof(ps[objn])=="object");
else return false;
}


//取派生关系数组,返回Array
this.Parents=function(){
if(!(this.___parents instanceof Array)) this.___parents=new Array();
return this.___parents;
}


//生成类的继承关系图,返回字符串
this.Tree=function() { return ClassTree(this); }


//显示类的结构,返回字符串
this.MembersMap=function() { return ClassMembers(this); }


//取得所有的方法名称,返回一个字符串数组
this.Methods=function()
{
var methodArr=new Array();
for(key in this){
if(typeof(this[key])=="function" && (!this.IsKeyWord(key))) methodArr.push(key);
}
return methodArr;
}


//取得所有的属性名称,返回一个字符串数组
this.Properties=function()
{
var PropArr=new Array();
for(key in this){
if(typeof(this[key])!="function" && (!this.IsKeyWord(key))) PropArr.push(key);
}
return PropArr;
}

this.IsKeyWord=function(str
)//是否是保留关键字
{
var s=new String("" + str);
if(s.indexOf("___",0)==0) return true;

var o=new JSClass();
if(typeof(o[s])=="function") return true
return false;
}
}

//////////tools funciton////////////////////////
//使一个类是JSClass的派生类

function Class(o)
{
if(typeof(o)=="object" && typeof(o.constructor)=="function" ) {
o.___class=JSClass;
o.___class();
return true;
}
return false;
}
 
//判断一个类是否JSClass的派生类
function isClass(o)
{
if(typeof(o)=="object" && typeof(o.constructor)=="function" ) {
if(typeof(o.___class)=="function" && o.___class===JSClass) return true;
}
return false;
}
 
//生成JSClass类的继承关系图,返回字符串
function ClassTree(jscObject)
{
var outputStr="";
function ___dump(objName,parentList,preString,isLast,InheritLevel)
{
var i=0;
if(InheritLevel>32) outputStr+=preString+"__"+objName+" ....../n";
else outputStr+=preString+"__"+objName+"/n";

if(parentList.length>0)
{
var newPreString=new String(preString);
if(isLast) newPreString=newPreString.replace(/[|]$/i,"");
newPreString+=" |";
i=0;
for(key in parentList) {
___dump(key,parentList[key],newPreString,(i==parentList.length-1),InheritLevel+1);
i++;
}
}
}

if(isClass(jscObject)) ___dump(jscObject.ClassName(),jscObject.Parents(),"",false,0);
else outputStr="NOT_JSCLASS_OBJECT";
return outputStr;
}
 
//显示JSClass类的结构,,返回字符串
function ClassMembers(jscObject)
{
var outputStr="";

if(isClass(jscObject))
{
outputStr+="class " + jscObject.ClassName() + "/n";
var m=jscObject.Methods();
var p=jscObject.Properties();
outputStr+="/n Methods/n";
for(key in m) { outputStr+=" |__ "+m[key]+"/n"; }
outputStr+="/n Properties/n";
for(key in p) { outputStr+=" |__ "+p[key]+"/n"; }
}
else outputStr="NOT_JSCLASS_OBJECT";
return outputStr;
}
//</SCRIPT>
 
在我的另一篇博文 [ JavaScript面向对象编程(2) :继承和封装] 中我尝试了另一种实现继承的方式并考虑了封装,有兴趣的可以看一下.