Javascript prototype 元语言编程

昨天发了一篇小文Javascript 匿名函数的一种应用:封装,没想到来自Tony Zhou的第一个回复就把我带入到Javascript的元编程领域。我以前使用过的语言中Python和lua是支持元编程的。他们都使用了一种类似元表的结构来实现元编程。js也有同样的机制,尝试之后发现,一点都不逊色。而js的元表就是prototype。先来看一段代码:

function A()
{
this.x = 10;
this.add = function(s)
{ this.x += s; }
}
a1 = new A();
alert(a1.x)//output 10
a1.add(10)
alert(a1.x)//output 20
a1.sub = function(s)
{ this.x -= s; }
a1.sub(10)
alert(a1.x)//output 10

 

上面的代码演示了js一个很基本的应用,允许实例动态增加成员。但是如果我希望每一A的实例都增加“sub”这个方法怎么办呢,显然在每次创建时自己增加是很麻烦的。现在prototype可以出场了:

 

A.prototype.sub = function(s)

{

  this.x -= s;

}

 

好了从这里开始所有A的实例包括已经创建的实例都自动增加了“sub”这个方法。

回到上一篇文章最后我提的问题:JS能够实现继承吗?这个问题也找到了答案,还是prototype。下面来看另外一段代码:

 

//基类
function A()
{
this.x = 10;
this.add = function(y)
{ this.x += y }
}


function B()
{
this.y = 10;
this.sub = function(x)
{ this.y -= x; }
}
B.prototype = new A();//在这里B继承了A


function C()
{
this.z = 10;
this.mul = function(s)
{ this.z *= s; }
}
C.prototype = new B();//在这里C继承了B


function printProt(tb)
{
str="Table = {\n";
for(var k in tb)
{
str += k + ":" + tb[k] + "\n";
}
str += "\n}";
alert(str);
}

printProt(C);//打印C的元表
x = new C();

//下面显示x的继承关系
alert("x is a C:" + (x instanceof C));
alert("x is a B:" + (x instanceof B));
alert("x is a A:" + (x instanceof A));


到这里一切似乎都明白了,但是我还是有点小疑问。我在打印元表时发现,如果不显示使用prototype的话,默认它是空的,例如:上面代码中的类A的成员“x”,“add”就不在A.prototype中。而Array等内建类型的元表默认也是空的。看见prototype在JS的世界里只是一个可选的技术,而且从一些文章来看,好像也并不收到推崇。

本文旨在解答Javascript的继承问题,虽然使用Javascript未必会用到继承,但是多了解手头工具的特性总是好的。

 

(最后我忍不住又有了个问题:

function F1(obj)

{

  obj.F2(); 

上面的函数接受一个对象,然后他认为该对象有一个叫F2的函数可供调用,但是这个对象很可能没有这个函数,于是F1需要对他进行检查:

 

function F1(obj)

{

  if(obj.F)

    obj.F2(); 

}

这种写法到处都能见到,管用但是丑陋。是不是有一种方法,当访问不存在的成员时,提供一种默认行为,而不是到处去检查? 

 

) 


 

posted on 2010-06-27 21:24  索夫特威尔  阅读(2048)  评论(2编辑  收藏  举报

导航