配色: 字号:
JavaScript基础之继承
2016-11-01 | 阅:  转:  |  分享 
  
JavaScript基础之继承

前些天写了一篇关于JavaScript基础的帖子"JavaScript基础之对象"。在那篇帖子中说马上就会写一些关于继承方面的东西。可是上周杂事太多,都没有时间动笔,就一直拖到今天才终于下笔写了。上一篇帖子中很多人认为我自己的东西太少了,所以这篇帖子中在说完基础知识之后我会给出一个完整的例子。



大家都知道面向对象语言的三大特性为:封装、继承、多态。面向对象的语言之所以强大就全依赖于这三大特性。脚本作为一种准面向对象的语言虽然有先天的不足,但还是能在某种程度上去实现这些特性。实现最多、技术最成熟的就数继承了,不过脚本也不能像C#一样简单地用一个":"就能实现继承,而是要自己去实现继承的细节。



1继承的几种实现方法



要实现继承首先就必须要有子类、父类(超类、基类等叫法)。子类去继承父类的方法和属性。在脚本里所有开发人员定义的类都可以作为父类,不过本地类(nativeobject)和宿主类(hostobject)不能作为父类。由于脚本里面没有访问修饰符,父类所有的属性和方法都可以被子类直接访问。子类也可以扩展父类的属性和方法。



1.1call()方法



Call方法是脚本的一个内置(buildin)方法。官方说明为:调用一个对象的方法,以另一个对象替换当前对象。语法为:call([thisObj[,arg1[,arg2[,[,.argN]]]]])。用这个方法可以很容易地模拟继承的实现:



类(funCreateElement)有一个属性(sAClassName)和一个方法(createALink)。它的作用是创建一个DOM元素。这个类使用this关键字给属性赋值,这样就确保了所有的实例指向的都是自己的值。



1functionfunCreateElement(sClassName)

2{

3this.sAClassName=sClassName;

4

5this.createALink=function()

6{

7varoA=document.createElement("a");

8oA.className=this.sAClassName;

9returnoA;

10}

11}





1functionfunCurrNavi()

2{

3//继承元素创建类

4funCreateElement.call(this,"tblNavigatorA");

5}

这样就实现了一个最简单的继承了。在funCurrNavi的实例里就可以直接使用funCreateElement类里面的方法了。



varo=newfunCurrNavi();

o.createALink();





1.2apply()方法



apply方法也是脚本的一个内置(buildin)方法。其用法和call对象类似。官方说明为:应用某一对象的一个方法,用另一个对象替换当前对象。语法为:apply([thisObj[,argArray]])。实际上这两个的作用几乎是相同的,要注意的地方是call(thisObj[,arg1[,arg2[,)中的arg参数可以是变量,而apply([thisObj[,argArray]])中的参数为数组集合。由于和call方法就只有参数的不同而已所以就不举例子了。





1.3原型链



Prototype对象是所有类的源头。如果修改了prototype类的方法则这个修改会反映到所有类的实例里面。比如:在string.prototype里面加一个方法trim(),String.prototype.trim=function(){}。那么所有的字符串都会具有trim()方法了("aa".trim())。由于prototype的这个特性,我们就可以实现继承方法了。如果用原型链的方式重定义前面的例子,它们将变为下面的形式:





这种方式采用funCurrNavi.prototype=newfunCreateElement()方法,将funCreateElement类里面所有的属性和方法都复制到funCurrNavi类里面。非常的快捷。这种方式虽然非常的快捷,但是也有其缺点。采用这种方式时子类所有的属性和方法都必须在funCurrNavi.prototype=newfunCreateElement()语句之后。因为该语句会覆盖funCurrNavi类原有的prototype类,添加了新的属性和方法的原有prototype类将被销毁。而且父类和子类都没有参数,只能通过设置属性的方法传入参数。



1functionfunCreateElement()

2{

3}

4

5funCreateElement.prototype.sAClassName=sClassName;//样式类

6funCreateElement.prototype.createALink=function()

7{

8varoA=document.createElement("a");

9oA.className=this.sAClassName;

10returnoA;

11}

12

13

14functionfunCurrNavi()

15{

16}

17

18funCurrNavi.prototype=newfunCreateElement();

19funCurrNavi.prototype.showMeInDiv=function()

20{

21}







1.4混合方式



混合方式就是指将前两种方式结合起来使用,取长避短。在call方式里面定义类的方式不理想,相同的方法在实例里面被重复的实例化了。原型链的方法则因为没有参数而不理想,使用参数前得额外的去设置其属性,不如构造函数的参数来的方便。根据上一篇帖子中定义类的混合方式,我们重新定义funCreateElement类:



1functionfunCreateElement(sClassName)

2{

3this.sAClassName=sClassName;

4}

5

6funCreateElement.prototype.createALink=function()

7{

8varoA=document.createElement("a");

9oA.className=this.sAClassName;

10returnoA;

11}



然后在funCurrNavi类里面采用call方式继承funCreateElement类的属性,采用原型链的方式继承其方法。如下:



1functionfunCurrNavi(sLinkText)

2{

3funCreateElement.call(this,"tblNavigatorA");

4

5this.LinkText=sLinkText;

6}

7

8funCurrNavi.prototype=newfunCreateElement();//继承超链接类

9

10funCurrNavi.prototype.showMeInDiv=function()

11{

12varoLink=this.createALink();

13oLink.text=this.LinkText;

14}

采用funCreateElement.call(this,"tblNavigatorA")方式继承其参数,funCurrNavi.prototype=newfunCreateElement()方式继承其方法。从而达到方法不会被实例化多次的目的。



2实例



前面讲述了几种继承的实现方式,这一小节就利用前面讲述的方法去练习一个小例子。这个例子是根据一个字符串去呈现一个树状的列表,这种需求常见于页面的导航中。由于只是为了辅助讲述继承,例子有些地方不免有些牵强附会和小题大做的地方。这些就希望各位网友包涵了,请各位珍惜自己的砖头了。我在这里戴上钢盔等候大家的批评了。:)



下面是其运行成功的样图:



左面的那个是用table作为容器,右边的那个是用div作为容器。







1

2

3CreateAdminPages''Navigator

4

5/导航table的样式/.tblNavigator

6{

7border:2pxsolid#FFD7AC;

8width:200px;

9margin:3px;

10background:#fff;

11margin-top:5px;

12margin-bottom:5px;

13border-collapse:collapse;

14}

15/每个根节点的样式/.tblNavigatorRoot

16{

17height:30px;

18line-height:30px;

19text-align:left;

20vertical-align:middle;

21}

22/根节点的子节点的样式/.tblNavigatorTD

23{

24border-collapse:collapse;

25border:1pxsolid#FFE6CB;

26height:22px;

27text-indent:15px;

28background:#fff;

29width:100%;

30}

31/导航中的超链接/.tblNavigatorA

32{

33font-weight:700;

34text-decoration:none;

35color:Black;

36width:100px;

37}

38

39

40

41

42

43

44

45

46

47

48varsNavigatorMain=

49{

50sNavigators:[

51{

52root:[{name:''root1''}],

53sons:[{name:''root1Son1'',url:''bcc''},{name:''root1Son2'',url:''bcc''}]

54},

55{

56root:[{name:''root2''}],

57sons:[{name:''root2Son1'',url:''bcc''}]

58},

59{

60root:[{name:''root3''}],

61sons:[{name:''root3Son1'',url:''bcc''},{name:''root3Son2'',url:''bcc''},{name:''root3Son3'',url:''bcc''}]

62},

63{

64root:[{name:''root4''}],

65sons:[{name:''root4Son1'',url:''bcc''},{name:''root4Son3'',url:''bcc''}]

66}

67,

68{

69root:[{name:''root4''}],

70sons:[{name:''root4Son1'',url:''bcc''},{name:''root4Son3'',url:''bcc''}]

71}

72]

73};

74

75/

76创建一个元素

77sClassName:元素的样式控制类

78/

79functionfunCreateElement(sClassName)

80{

81//样式类

82this.sAClassName=sClassName;

83}

84

85/

86创建超链接元素

87sText:超链接显示的文本

88sUrl:超链接的href

89sTarget:打开链接的目标

90返回:超链接元素

91/

92funCreateElement.prototype.createALink=function(sText,sUrl,sTarget)

93{

94varoA=document.createElement("a");

95oA.href=sUrl;//链接文本

96oA.className=this.sAClassName;//样式类

97oA.target=sTarget;//打开链接的目标

98oA.appendChild(document.createTextNode(sText));//显示文本

99

100returnoA;

101}

102

103/

104创建Div元素

105sText:显示的文本

106返回:Div元素

107/

108funCreateElement.prototype.createDivBlank=function()

109{

110varoDiv=document.createElement("div");

111oDiv.className=this.sAClassName;

112returnoDiv;

113}

114

115/

116创建Div元素

117sText:显示的文本

118返回:Div元素

119/

120funCreateElement.prototype.createDivNoLink=function(sText)

121{

122varoDiv=document.createElement("div");

123oDiv.className=this.sAClassName;

124oDiv.appendChild(document.createTextNode(sText));

125

126returnoDiv;

127}

128

129/

130创建一个模块的节点

131oNaviJSON:一个模块节点的文本

132oParentObject:父节点

133sClassNameRoot:根节点的样式类

134sClassNameNode:子节点的样式类

135/

136functionfunCurrNavi(oNaviJSON,oParentObject,sClassNameRoot,sClassNameNode)

137{

138//继承元素创建类

139funCreateElement.call(this,"tblNavigatorA");

140

141//当前导航的菜单

142this.oNavi=oNaviJSON;

143//当前导航的父节点

144this.oParent=oParentObject;

145//根节点的样式类

146this.oNClassNameRoot=sClassNameRoot;

147//子节点的样式类

148this.oNClassNameNode=sClassNameNode;

149}

150

151//继承超链接类

152funCurrNavi.prototype=newfunCreateElement();

153

154//显示自己(在Table容器里)

155funCurrNavi.prototype.showMeInTable=function()

156{

157//在父容器中添加一行,并将父节点写入

158this.oParent.insertRow(0);

159this.oParent.rows[0].onclick=function(){alert(this.innerText)};

160this.oParent.rows[0].insertCell(0);

161this.oParent.rows[0].cells[0].className=this.oNClassName;

162this.oParent.rows[0].cells[0].appendChild(document.createTextNode(this.oNavi.root[0].name));

163

164varj=this.oNavi.sons.length;

165for(vari=0;i
166{

167this.oParent.insertRow(i+1);

168this.oParent.rows[i+1].insertCell(0);

169this.oParent.rows[i+1].cells[0].className=this.oNClassNameNode;

170this.oParent.rows[i+1].cells[0].appendChild(this.createALink(this.oNavi.sons[i].name,this.oNavi.sons[i].url,"_blank"));

171}

172}

173

174//显示自己(在Div容器里)返回:div

175funCurrNavi.prototype.showMeInDiv=function()

176{

177//创建一个暂时的容器

178varoDivContainer=document.createElement("div");

179

180//在父容器中将父节点写入

181varoDivRoot=this.createDivNoLink(this.oNavi.root[0].name);

182oDivRoot.className=this.oNClassNameRoot;

183oDivRoot.onclick=function(){alert(this.innerText);};

184oDivContainer.appendChild(oDivRoot);

185

186//链接节点

187varoDivLinkNode;

188

189varj=this.oNavi.sons.length;

190for(vari=0;i
191{

192oDivLinkNode=this.createDivBlank();

193oDivLinkNode.appendChild(this.createALink(this.oNavi.sons[i].name,this.oNavi.sons[i].url,"_blank"));

194oDivLinkNode.className=this.oNClassNameNode;

195oDivContainer.appendChild(oDivLinkNode);

196}

197

198returnoDivContainer;

199}

200

201

202/

203创建所有的节点

204oNavisJSON:所有节点的文本

205/

206functionfunCurrNavis(oNavisJSON,sClassName)

207{

208//当前导航的菜单

209this.oNavis=oNavisJSON;

210//样式类

211this.oNsClassName=sClassName;

212}

213

214//创建所有的节点(以Table为容器)

215funCurrNavis.prototype.createNavigatorsInTable=function()

216{

217//创建父Table

218varoTable=document.createElement("table");

219oTable.className=this.oNsClassName;

220

221//创建tbody

222varoTBody=document.createElement("tbody");

223oTable.appendChild(oTBody);

224

225varj=this.oNavis.sNavigators.length;

226varCNavi;

227

228for(vari=j-1;i>=0;i--)

229{

230CNavi=newfunCurrNavi(this.oNavis.sNavigators[i],oTBody,"tblNavigatorRoot","tblNavigatorTD");

231CNavi.showMeInTable();

232}

233

234returnoTable;

235}

236

237//创建所有的节点(以Div为容器)

238funCurrNavis.prototype.createNavigatorsInDiv=function()

239{

240//创建容器

241varoContainer=document.createDocumentFragment();

242

243varj=this.oNavis.sNavigators.length;

244varCNavi;

245

246for(vari=0;i
247{

248CNavi=newfunCurrNavi(this.oNavis.sNavigators[i],{},"tblNavigatorRoot","tblNavigatorTD");

249oContainer.appendChild(CNavi.showMeInDiv());

250}

251

252returnoContainer;

253}

254

255/

256供调用的函数

257sNavigatorMain:所有节点的文本

258sParentID:导航父容器的ID

259/

260functionshowNavigator(sNavigatorMain,sParentID,sFlag)

261{

262varoTemp=eval("ddkk="+sNavigatorMain);

263varmain=newfunCurrNavis(oTemp,"tblNavigator");

264

265if(sFlag=="div")

266{

267document.getElementById(sParentID).appendChild(main.createNavigatorsInDiv());

268}

269else

270{

271document.getElementById(sParentID).appendChild(main.createNavigatorsInTable());

272}

273}

274

275

276

277

278//showNavigator("{sNavigators:[{root:[{name:''用户管理''}],sons:[{name:''个人信息管理'',url:''~/UserMng/frmMyInfoMng.aspx''},{name:''本单位用户管理'',url:''~/UserMng/frmUserMng.aspx''},{name:''本单位信息管理'',url:''~/SysMaintenance/frmDeptInfo.aspx''}]},{root:[{name:''申报管理''}],sons:[{name:''项目管理'',url:''~/Declaration/frmProjAppMng.aspx''}]},{root:[{name:''留言板管理''}],sons:[{name:''给管理员留言'',url:''~/Information/frmQuestion.aspx''}]}]}","divMain","table");

279

280//showNavigator("{sNavigators:[{root:[{name:''用户管理''}],sons:[{name:''个人信息管理'',url:''~/UserMng/frmMyInfoMng.aspx''},{name:''本单位用户管理'',url:''~/UserMng/frmUserMngwww.wang027.com.aspx''},{name:''本单位信息管理'',url:''~/SysMaintenance/frmDeptInfo.aspx''}]},{root:[{name:''申报管理''}],sons:[{name:''项目管理'',url:''~/Declaration/frmProjAppMng.aspx''}]},{root:[{name:''留言板管理''}],sons:[{name:''给管理员留言'',url:''~/Information/frmQuestion.aspx''}]}]}","divMain2","div");

281

282

283

284

在这个实例里面采用了JSON字符串作为数据源"{sNavigators:[{root:[{name:''用户管理''}],sons:[{name:''个人信息管理'',url:''~/UserMng/frmMyInfoMng.aspx''},{name:''本单位用户管理'',url:''~/UserMng/frmUserMng.aspx''},{name:''本单位信息管理'',url:''~/SysMaintenance/frmDeptInfo.aspx''}]},{root:[{name:''申报管理''}],sons:[{name:''项目管理'',url:''~/Declaration/frmProjAppwww.baiyuewang.netMng.aspx''}]},{root:[{name:''留言板管理''}],sons:[{name:''给管理员留言'',url:''~/Information/frmQuestion.aspx''}]}]}"。其格式好了的形式类似于上面例子中的



1varsNavigatorMain=

2{

3sNavigators:[

4{

5root:[{name:''root1''}],

6sons:[{name:''root1Son1'',url:''bcc''},{name:''root1Son2'',url:''bcc''}]

7},

8{

9root:[{name:''root2''}],

10sons:[{name:''root2Son1'',url:''bcc''}]

11},

12{

13root:[{name:''root3''}],

14sons:[{name:''root3Son1'',url:''bcc''},{name:''root3Son2'',url:''bcc''},{name:''root3Son3'',url:''bcc''}]

15},

16{

17root:[{name:''root4''}],

18sons:[{name:''root4Son1'',url:''bcc''},{name:''root4Son3'',url:''bcc''}]

19}

20,

21{

22root:[{name:''root4''}],

23sons:[{name:''root4Son1'',url:''bcc''},{name:''root4Son3'',url:''bcc''}]

24}

25]

26};

用JSON字符串作为数据源非常的方便,他能直接转化成类。上面的例子非常简单就不详细地说明了,通过注释就能看明白了。

献花(0)
+1
(本文系thedust79首藏)