分类归档: Programming

编程编程编程。。。

【转】推荐的C++书籍以及阅读顺序

当读者有一定c/c++基础
推荐的阅读顺序:
level 1
从<<essential c++>>开始,短小精悍,可以对c++能进一步了解其特性
以<<c++ primer>>作字典和课外读物,因为太厚不可能一口气看完

level 2
然后从<<effective c++>>开始转职,这是圣经,请遵守10诫,要经常看,没事就拿来翻翻
接着是<<exceptional c++>>,个人认为Herb Sutter主席大人的语言表达能力不及Scott Meyers总是在教育第一线的好
顺下来就是<<more effective c++>>和<<more exceptional c++>>,请熟读并牢记各条款
当你读到这里,应该会有一股升级的冲动了

level 3
<<insied the c++ object model>>看过后如一缕清风扫去一直以来你对语言的疑惑,你终于能明白compiler到底都背着你做了些什么了,这本书要细细回味,比较难啃,最好反复看几遍,加深印象
看完上一本之后,这本<<The design and evolution of c++>>会重演一次当年C++他爹在设计整个语言过程中的历程

level 4
<<the c++ standard library>>是stl的字典,要什么都可以查得到
学c++不能不学stl,那么首先是<<effective stl>>,它和圣经一样是你日常行为的规范
<<generic programming and the stl>>让你从oo向gp转变
光用不行,我们还有必要了解stl的工作原理,那么<<stl源码剖析>>会解决你所有的困惑

level 5
对于c++无非是oo和gp,想进一步提升oo,<<exeptional c++ style>>是一本主席这么多年的经验之谈,是很长esp的
一位stl高手是不能不去了解template的,<<c++ template>>是一本百科全书,足够你看完后对于gp游刃有余
<<modern c++ design>>是太过聪明的人写给明眼人看的

好书有很多,不能一一列举
以上我的读书经历,供各位参考。接下来的无非就是打怪练级,多听多写多看;boost、stl、loki这些都是利器,斩妖除魔,奉劝各位别再土法练钢了。

at last,无他,唯手熟尔。

忘了一本《thinking in C++》
也是经典系列之一

< <effective c++>>这本圣经的作者Scott Meyesr在给<<modern c++ design>>序言的时候高度的赞赏了Andrei同志的工作:C++社群对template的理解即将经历一次巨大的变化,我对它所说 的任何事情,也许很快就会被认为是陈旧的、肤浅的、甚至是完全错的。
就我所知,template的世界还在变化,速度之快就像我1995年回避写 它的时候一样。从发展的速度来看,我可能永远不会写有关template的技术书籍。幸运的是一些人比我勇敢,Andrei就是这样一位先锋。我想你会从 此书得到很多收获。我自己就得到了很多——Scott Meyers September2000。

并且,Scott Meyers 在最 近的Top5系列文章中,评价C++历史里面最重要5本书中、把Modern C++ Design列入其中,另外四本是它自己的effective c ++、以及C++ Programming Language、甚至包括《设计模式》和《C++标准文档》。
显然,Scott Meyers已经作为一个顶尖大师的角度承认了<<modern c++ design>>的价值。

并且调侃地说,可以把是否使用其中模板方法定义为,现代C++使用者和非现代C++使用者,并且检讨了自己在早期版本Effective对模板的忽视,最后重申在新版本Effective第七章节加入大量对模板程序设计的段落,作为对这次失误的补偿。

并 且,在这里要明确的是<<modern c++ design>>并不是一本泛型编成的书,也不是一本模板手册。其中提出了基于 策略的设计方法,有计划和目的的使用了模板、面向对象和设计模式。虽然Andrei本人对模板的研究世界无人能敌,但对其他领域的作为也令人赞叹。

任何做游戏的人都不能忽视OpenAL把,你在开发者的名单里能看到Loki的名字:)

Read: 903

在数据库中存储层次数据

作者:Gijs Van Tulder
翻译:ShiningRay @ NirvanaStudio

无论你要构建自己的论坛,在你的网站上发布消息还是书写自己的cms [1]程序,你都会遇到要在数据库中存储层次数据的情况。同时,除非你使用一种像XML [2]的数据库,否则关系数据库中的表都不是层次结构的,他们只是一个平坦的列表。所以你必须找到一种把层次数据库转化的方法。

存储树形结构是一个很常见的问题,他有好几种解决方案。主要有两种方法:邻接列表模型和改进前序遍历树算法

在本文中,我们将探讨这两种保存层次数据的方法。我将举一个在线食品店树形图的例子。这个食品店通过类别、颜色和品种来组织食品。树形图如下:

1105_tree

本文包含了一些代码的例子来演示如何保存和获取数据。我选择PHP [3]来写例子,因为我常用这个语言,而且很多人也都使用或者知道这个语言。你可以很方便地把它们翻译成你自己用的语言。

邻接列表模型(The Adjacency List Model)

我们要尝试的第一个——也是最优美的——方法称为“邻接列表模型”或称为“递归方法”。它是一个很优雅的方法因为你只需要一个简单的方法来在你的树中进行迭代。在我们的食品店中,邻接列表的表格如下:

1105_table1

如你所见,对每个节点保存一个“父”节点。我们可以看到“Pear [4]”是“Green”的一个子节点,而后者又是“Fruit”的子节点,如此类推。根节点,“Food”,则他的父节点没有值。为了简单,我只用了“title”值来标识每个节点。当然,在实际的数据库中,你要使用数字的ID。

显示树

现在我们已经把树放入数据库中了,得写一个显示函数了。这个函数将从根节点开始——没有父节点的节点——同时要显示这个节点所有的子节点。对于这些子节点,函数也要获取并显示这个子节点的子节点。然后,对于他们的子节点,函数还要再显示所有的子节点,然后依次类推。

也许你已经注意到了,这种函数的描述,有一种普遍的模式。我们可以简单地只写一个函数,用来获得特定节点的子节点。这个函数然后要对每个子节点调用自身来再次显示他们的子节点。这就是“递归”机制,因此称这种方法叫“递归方法”。

<?php
// $parent 是我们要查看的子节点的父节点
// $level 会随着我们深入树的结构而不断增加,
// 用来显示一个清晰的缩进格式
function display_children($parent, $level) {
// 获取$parent的全部子节点
$result = mysql_query('SELECT title FROM tree '.
'WHERE parent="'.$parent.'";');

// 显示每个节点
while ($row = mysql_fetch_array($result)) {
// 缩进并显示他的子节点的标题
echo str_repeat(' ',$level).$row['title']."n";

// 再次调用这个函数来显着这个子节点的子节点
display_children($row['title'], $level+1);
}
}
?>

要实现整个树,我们只要调用函数时用一个空字符串作为$parent$level = 0: display_children('',0); 函数返回了我们的食品店的树状图如下:

Food
Fruit
Red
Cherry
Yellow
Banana
Meat
Beef
Pork

注意如果你只想看一个子树,你可以告诉函数从另一个节点开始。例如,要显示“Fruit”子树,你只要display_children('Fruit',0);

The Path to a Node节点的路径

利用差不多的函数,我们也可以查询某个节点的路径如果你只知道这个节点的名字或者ID。例如,“Cherry”的路径是“Food”> “Fruit”>“Red”。要获得这个路径,我们的函数要获得这个路径,这个函数必须从最深的层次开始:“Cheery”。但后查找这个节点的父 节点,并添加到路径中。在我们的例子中,这个父节点是“Red”。如果我们知道“Red”是“Cherry”的父节点。

<?php
// $node 是我们要查找路径的那个节点的名字
function get_path($node) {
// 查找这个节点的父节点
$result = mysql_query('SELECT parent FROM tree '.
'WHERE title="'.$node.'";');
$row = mysql_fetch_array($result);

// 在这个array [5] 中保存数组
$path = array();

// 如果 $node 不是根节点,那么继续
if ($row['parent']!='') {
// $node 的路径的最后一部分是$node父节点的名称
$path[] = $row['parent'];

// 我们要添加这个节点的父节点的路径到现在这个路径
$path = array_merge(get_path($row['parent']), $path);
}

// 返回路径
return $path;
}
?>

这个函数现在返回了指定节点的路径。他把路径作为数组返回,这样我们可以使用print_r(get_path('Cherry')); 来显示,其结果是:

Array
(
[0] => Food
[1] => Fruit
[2] => Red
)

不足

正如我们所见,这确实是一个很好的方法。他很容易理解,同时代码也很简单。但是邻接列表模型的缺点在哪里呢?在大多数编程语言中,他运行很慢,效率很差。这主要是“递归”造成的。我们每次查询节点都要访问数据库。

每次数据库查询都要花费一些时间,这让函数处理庞大的树时会十分慢。

造成这个函数不是太快的第二个原因可能是你使用的语言。不像Lisp这类语言,大多数语言不是针对递归函数设计的。对于每个节点,函数都要调用他自 己,产生新的实例。这样,对于一个4层的树,你可能同时要运行4个函数副本。对于每个函数都要占用一块内存并且需要一定的时间初始化,这样处理大树时递归 就很慢了。

改进前序遍历树

现在,让我们看另一种存储树的方法。递归可能会很慢,所以我们就尽量不使用递归函数。我们也想尽量减少数据库查询的次数。最好是每次只需要查询一次。

我们先把树按照水平方式摆开。从根节点开始(“Food”),然后他的左边写上1。然后按照树的顺序(从上到下)给“Fruit”的左边写上2。这 样,你沿着树的边界走啊走(这就是“遍历”),然后同时在每个节点的左边和右边写上数字。最后,我们回到了根节点“Food”在右边写上18。下面是标上 了数字的树,同时把遍历的顺序用箭头标出来了。

1105_numbering

我们称这些数字为左值和右值(如,“Food”的左值是1,右值是18)。正如你所见,这些数字按时了每个节点之间的关系。因为“Red”有3和6 两个值,所以,它是有拥有1-18值的“Food”节点的后续。同样的,我们可以推断所有左值大于2并且右值小于11的节点,都是有2-11的 “Food”节点的后续。这样,树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做“改进前序遍历树”算法。

在继续前,我们先看看我们的表格里的这些值:

1105_table2

注意单词“left”和“right”在SQL中有特殊的含义。因此,我们只能用“lft”和“rgt”来表示这两个列。(译注——其实Mysql 中可以用“`”来表示,如“`left`”,MSSQL中可以用“[]”括出,如“[left]”,这样就不会和关键词冲突了。)同样注意这里我们已经不 需要“parent”列了。我们只需要使用lft和rgt就可以存储树的结构。

获取树

如果你要通过左值和右值来显示这个树的话,你要首先标识出你要获取的那些节点。例如,如果你想获得“Fruit”子树,你要选择那些左值在2到11的节点。用SQL语句表达:

SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;

这个会返回:

1105_table3

好吧,现在整个树都在一个查询中了。现在就要像前面的递归函数那样显示这个树,我们要加入一个ORDER BY子句在这个查询中。如果你从表中添加和删除行,你的表可能就顺序不对了,我们因此需要按照他们的左值来进行排序。

SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;

就只剩下缩进的问题了。

要显示树状结构,子节点应该比他们的父节点稍微缩进一些。我们可以通过保存一个右值的一个栈。每次你从一个节点的子节点开始时,你把这个节点的右值 添加到栈中。你也知道子节点的右值都比父节点的右值小,这样通过比较当前节点和栈中的前一个节点的右值,你可以判断你是不是在显示这个父节点的子节点。当 你显示完这个节点,你就要把他的右值从栈中删除。要获得当前节点的层数,只要数一下栈中的元素。

<?php
function display_tree($root) {
// 获得$root节点的左边和右边的值
$result = mysql_query('SELECT lft, rgt FROM tree '.
'WHERE title="'.$root.'";');
$row = mysql_fetch_array($result);

// 以一个空的$right栈开始
$right = array();

// 现在,获得$root节点的所有后序
$result = mysql_query('SELECT title, lft, rgt FROM tree '.
'WHERE lft BETWEEN '.$row['lft'].' AND '.
$row['rgt'].' ORDER BY lft ASC;');

// 显示每一行
   while ($row = mysql_fetch_array($result)) {
     // 检查栈里面有没有元素
     if (count($right)>0) {
       // 检查我们是否需要从栈中删除一个节点
       while ($right[count($right)-1]<$row['rgt']) {
         array_pop($right);
       }
     }

     // 显示缩进的节点标题
     echo str_repeat(' ',count($right)).$row['title']."n";

     // 把这个节点添加到栈中
     $right[] = $row['rgt'];
   }
}
?>

如果运行这段代码,你可以获得和上一部分讨论的递归函数一样的结果。而这个函数可能会更快一点:他不采用递归而且只是用了两个查询

节点的路径

有了新的算法,我们还要另找一种新的方法来获得指定节点的路径。这样,我们就需要这个节点的祖先的一个列表。

由于新的表结构,这不需要花太多功夫。你可以看一下,例如,4-5的“Cherry”节点,你会发现祖先的左值都小于4,同时右值都大于5。这样,我们就可以使用下面这个查询:

SELECT title FROM tree WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;

注意,就像前面的查询一样,我们必须使用一个ORDER BY子句来对节点排序。这个查询将返回:

+-------+
| title |
+-------+
| Food |
| Fruit |
| Red   |
+-------+

我们现在只要把各行连起来,就可以得到“Cherry”的路径了。

有多少个后续节点?How Many Descendants

如果你给我一个节点的左值和右值,我就可以告诉你他有多少个后续节点,只要利用一点点数学知识。

因为每个后续节点依次会对这个节点的右值增加2,所以后续节点的数量可以这样计算:

descendants = (right – left - 1) / 2

利用这个简单的公式,我可以立刻告诉你2-11的“Fruit”节点有4个后续节点,8-9的“Banana”节点只是1个子节点,而不是父节点。

自动化树遍历

现在你对这个表做一些事情,我们应该学习如何自动的建立表了。这是一个不错的练习,首先用一个小的树,我们也需要一个脚本来帮我们完成对节点的计数。

让我们先写一个脚本用来把一个邻接列表转换成前序遍历树表格。

<?php
function rebuild_tree($parent, $left) {
// 这个节点的右值是左值加1
$right = $left+1;

// 获得这个节点的所有子节点
$result = mysql_query('SELECT title FROM tree '.
'WHERE parent="'.$parent.'";');
while ($row = mysql_fetch_array($result)) {
// 对当前节点的每个子节点递归执行这个函数
// $right 是当前的右值,它会被rebuild_tree函数增加
$right = rebuild_tree($row['title'], $right);
}

// 我们得到了左值,同时现在我们已经处理这个节点我们知道右值的子节点
mysql_query('UPDATE tree SET lft='.$left.', rgt='.
$right.' WHERE title="'.$parent.'";');

// 返回该节点的右值+1
return $right+1;
}
?>

这是一个递归函数。你要从rebuild_tree('Food',1); 开始,这个函数就会获取所有的“Food”节点的子节点。

如果没有子节点,他就直接设置它的左值和右值。左值已经给出了,1,右值则是左值加1。如果有子节点,函数重复并且返回最后一个右值。这个右值用来作为“Food”的右值。

递归让这个函数有点复杂难于理解。然而,这个函数确实得到了同样的结果。他沿着树走,添加每一个他看见的节点。你运行了这个函数之后,你会发现左值和右值和预期的是一样的(一个快速检验的方法:根节点的右值应该是节点数量的两倍)。

添加一个节点

我们如何给这棵树添加一个节点?有两种方式:在表中保留“parent”列并且重新运行rebuild_tree() 函数——一个很简单但却不是很优雅的函数;或者你可以更新所有新节点右边的节点的左值和右值。

第一个想法比较简单。你使用邻接列表方法来更新,同时使用改进前序遍历树来查询。如果你想添加一个新的节点,你只需要把节点插入表格,并且设置好parent列。然后,你只需要重新运行rebuild_tree() 函数。这做起来很简单,但是对大的树效率不高。

第二种添加和删除节点的方法是更新新节点右边的所有节点。让我们看一下例子。我们要添加一种新的水果——“Strawberry”,作为“Red” 的最后一个子节点。首先,我们要腾出一个空间。“Red”的右值要从6变成8,7-10的“Yellow”节点要变成9-12,如此类推。更新“Red” 节点意味着我们要把所有左值和右值大于5的节点加上2。

我们用一下查询:

UPDATE tree SET rgt=rgt+2 WHERE rgt>5;
UPDATE tree SET lft=lft+2 WHERE lft>5;

现在我们可以添加一个新的节点“Strawberry”来填补这个新的空间。这个节点左值为6右值为7。

INSERT INTO tree SET lft=6, rgt=7, title='Strawberry';

如果我们运行display_tree() 函数,我们将发现我们新的“Strawberry”节点已经成功地插入了树中:

Food
Fruit
Red
Cherry
Strawberry
Yellow
Banana
Meat
Beef
Pork

缺点

首先,改进前序遍历树算法看上去很难理解。它当然没有邻接列表方法简单。然而,一旦你习惯了左值和右值这两个属性,他就会变得清晰起来,你可以用这 个技术来完成临街列表能完成的所有事情,同时改进前序遍历树算法更快。当然,更新树需要很多查询,要慢一点,但是取得节点却可以只用一个查询。

总结

你现在已经对两种在数据库存储树方式熟悉了吧。虽然在我这儿改进前序遍历树算法性能更好,但是也许在你特殊的情况下邻接列表方法可能表现更好一些。这个就留给你自己决定了

最后一点:就像我已经说得我部推荐你使用节点的标题来引用这个节点。你应该遵循数据库标准化的基本规则。我没有使用数字标识是因为用了之后例子就比较难读。

进一步阅读

数据库指导 Joe Celko写的更多关于SQL数据库中的树的问题:
http://searchdatabase.techtarget.com/tip/1,289483,sid13_gci537290,00.html [6]

另外两种处理层次数据的方法:
http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html [7]

Xindice, “本地XML数据库”:
http://xml.apache.org/xindice/ [8]

递归的一个解释:
http://www.strath.ac.uk/IT/Docs/Ccourse/subsection3_9_5.html [9]

Read: 1285

树形结构问题的一种解决办法

在一个标准的树形结构里面,一般要想知道的操作基本上有查询子树和查询所有父树(路径),还有就是查询子树自身的深度问题,通过前些日子的总结发现一种结构可以很好的满足这些要求。
id parentID   name        path
———————————-
1     0              图书          0,1
2     1      
      管理类       0,1,2
3     2      
     名家作品     0,1,2,3
4     2      
     国内          0,1,2,4
5     2      
     外国          0,1,2,5
6     0      
     文学类       0,6
7     6      
     小说          0,6,7

上面这种结构就是我推荐的,这种结构对于我们通常用的id-parentID结构增加了一个路径(path)列,好处就是可以直接通过查询path列来找 出某个节点的子树和路径,比如2号节点的子树可以通过先查2号子树的path,然后再用like ‘0,1,2%’方式来得到。其路径可以通过in(0,1,2)查询到。深度可以通过explode(‘,’,$path),然后看看数组个数就可以看出 节点的深度了,这样就可以构建出一个树形结构了。
path列的构建可以在原有id-parentID结构上增加,通过id和parentid可以很方便的构建出某个节点的子树的path列(需要递归算法)。
常用的函数可以有三个:
nav($node) 根据节点求出其路径,先找出节点path然后根据path用"select * from category where id in ($path)",就能求出其路径所有节点了,方便导航。
tree($node)根据节点求出其所有子树,先找出节点path,然后用"select * from category where path like ‘$path%’",就可以找出所有子节点啦,这里可以通过计算每个节点的path中有几个元素explode(‘,’$path)计算每个节点的深度。
re_path($node)根据节点,重新构建子树的path,这个需要利用ID和ParentID两列,利用递归逐步计算,因为只有在改变子树隶属关系和建立新节点的时候用到,所以计算量应该不是很多。
好了上面是这种算法的基本构想,大家有什么新的构想,提出来讨论一下。

“改进前序遍历树”方法,这里有相关中文翻译介绍,http://www.nirvanastudio.org/category/database/
我这里提的方法很像“邻接列表模型”,就是增加了一个path列,所以针对邻接列表模型所遇到的最大的问题,子树、路径和深度问题得到了改善。
而改进前序遍历树方法也是有很大的局限的,就是当某个节点变换父节点时需要做大量的修改左右数值。而上面的方法修改量要小一点!
不知道这么说是否妥当,请指教!

附常用的三个函数:
function nav($id,$db){
$rs=$db->query("select * from category where id=’".$id."’");
$row=$rs->fetch();
$rs=$db->query("select * from category where id in (".$row[‘path’].") order by path");
return $rs->fetchall();
}
function tree($id,$db){
$rs=$db->query("select * from category where id=’".$id."’");
$row=$rs->fetch();
$rs=$db->query("select * from category where path like ‘".$row[‘path’]."%’ order by path");
$tree=$rs->fetchall();
foreach($tree as $key=>$row){
$depth=explode(‘,’,$row[‘path’]);
$depth=count($depth);
$tree[$key][‘depth’]=$depth;
}
return $tree;
}

function re_path($id,$parentpath=”,$db){//此函数使用前需要先获得父节点的path
       if($parentpath<>”){$path=$parentpath.’,’.$id;}else{$path=$id;}
$sql="update category set path=’".$path."’ where id=’"$id"’";
$rs=$db->query($sql);

$sql="select * from category where parentid=’".$id."’";
$rs=$db->query($sql);
while($row=$rs->fetch()){
   re_path($row[‘id’],$path,$db);
}
}

Read: 878

patTemplate模板类的使用实例


前面讲了一个phplib的使用,作为模板驱动的代表patTemplate一样有着稳定,快速开发等等的优点,下面介绍一个简单实用的例子,我们使用test.php来解析模板test.html 并使用patTemplate作为模板引擎

test.html 模板文件:

<patTemplate:tmpl name="article">
<html>
<head>
<title>A patTemplate example</title>
</head>
<body>
<h3>{HEADLINE}</h3>
{CONTENT}
</body>
</html>
</patTemplate:tmpl>

其中的变量headlinecontent是需要我们通过patTemplate来解析过来的

test.php文件:

<?PHP
//包含进模板类文件
include("includes/patTemplate.php");  
// 初始化模板对象
$tmpl = new patTemplate();  
// 设定模板文件目录
$tmpl->setBasedir("templates");  
// 设定使用的模板文件
$tmpl->readTemplatesFromFile("example1.tmpl.html");  
// 向模板添加变量
$tmpl->addVar("article", "HEADLINE", "This is the headline");
$tmpl->addVar("article", "CONTENT", "And this is the content…");  
// 最终解析并显示模板
$tmpl->displayParsedTemplate("article");
?>  

这是最简单的一个例子,当然如果你熟悉PHPLIB的话,那么也可以轻松的在patTemplate里面使用象PHPLIB一样的循环结构,后面再介绍吧

Read: 147

JavaScript中类的定义[2]

4.使用prototype原型对象定义类成员

使用prototype对象来定义类成员可以避免每实例化一个对象就创建一次类成员的缺点。 

new一个function时,prototype对象的成员将自动赋给所创建的对象。

Demo2

是一个JavaScript对象,可以为prototype对象添加、修改、删除方法和属性。从而为一个类添加成员定义。   

<script language=”JavaScript” type=”text/javascript”>
<!– //定义一个只有一个属性caption的类 
function cls(){  
this.caption=1;  
}  
//使用函数的prototype属性给类定义新成员 
cls.prototype.showcaption = function(){   alert(this.caption);  }  
//创建cls的一个实例 
var obj=new cls();
//调用通过prototype原型对象定义的showcaption方法 
obj.showcaption();
//–>
</script>   

prototype

了解了函数的prototype对象,现在再来看new的执行过程。   

1>创建一个新的对象,并让this指针指向它;   

2>将函数的prototype对象的所有成员都赋给这个新对象;   

3>执行函数体,对这个对象进行初始化操作;   

4>返回(1)中创建的对象。   

prototype对象的所有成员初始化过程发生在函数体(构造器)执行之前,所以可以在函数体内部调用prototype中定义的属性和方法。

Demo3

<script language=JavaScript type=text/javascript
!– //定义一个只有一个属性caption的类
function cls(){  this.caption=1;  this.showcaption(); }
//使用函数的prototype属性给类定义新成员
cls.prototype.showcaption=function(){  alert(this.caption); }
//创建cls的一个实例
var obj1=new cls(); //–>
/script>  

 

和上一段代码相比,这里在cls的内部调用了prototype中定义的方法showcaption,从而在对象的构造过程中就弹出了对话框,显示caption属性的值为1  

需要注意,原型对象的定义必须在创建类实例的语句之前,否则它将不会起作用。

Demo4

showcaption方法,就是因为该方法的定义是在实例化一个类的语句之后。   

<script language=”JavaScript” type=”text/javascript”>
<!– //定义一个只有一个属性caption的类
function cls(){  
this.caption=1;  
this.showcaption();
}
//创建cls的一个实例
var obj=new cls();
//在创建实例的语句之后使用函数的prototype属性给类定义新成员,只会对后面创建的对象有效
cls.prototype.showcaption=function(){  alert(this.caption); }
//–>
</script>   

这段代码将会产生运行时错误,显示对象没有

由此可见,prototype对象专用于设计类的成员,它是和一个类紧密相关的。

除此之外,prototype还有一个重要的属性:constructor,表示对该构造函数的引用,例如:

function cls(){  
alert(1);
}
cls.prototype.constructor(); //调用类的构造函数

  

这段代码运行后将会出现对话框,在上面显示文字“1”,从而可以看出一个prototype是和一个类的定义紧密相关的。

实际上:cls.prototype.constructor===cls  

Read: 776