JavaScript面向对象之属性实现javascript

来源:互联网 发布:重装系统哪个软件好 编辑:程序博客网 时间:2024/05/16 01:20

作者:truly

日期:2007.8.3

在我前面一篇文章《在javascript中使用面向对象》中我们介绍了msdn的一篇文章《使用面向对象的技术创建高级 web 应用程序》,作者简单介绍了javascript面向对象的一些关键技术,但是作者在讲到闭包概念的时候犯了一个明显的错误:“正常情况下,无法从函数以外访问函数内的本地变量。函数退出之后,由于各种实际原因,该本地变量将永远消失”详见原文。事实上这段描述是错误的。

请先看如下代码:

script>

function test(abc)

{

this.g = function(){debugger;};

}

var p = new test(2);

p.g();

script>

如果你启用了ie的调试功能,并安装了脚本调试器,例如vs,那么你在程序提示调试的时候进入调试,此时你可以醒目的发现abc依然存在,并且完好的保存了正确的值,而并非永远消失。但是这也不是我本文要讨论的重点,只是希望大家以后能够多动手,多实践,像ms asp.net ajax 团队的软件设计工程师都会犯这种错误,更何况诸位呢?

本文要讨论的是面向对象编程中常用的属性,但是在javascript中属性则无法像高级编程语言那样可以直接使用,看起来更像方法,这种实现方式也有人称之为闭包,但本文以属性相称。

属性是对私有变量的一种保护手段,同时提供了像public变量一样的使用效果,近代的高级编程语言例如c#和java都支持了属性这一特点。

我们知道,函数的入口参数被声明为该函数的本地变量,而对于本地变量,像我前面《在javascript中使用面向对象》关于全局变量和局部变量中描述的那样,由于其作用域仅限于函数内部,所有无法在外部对其进行访问,例如p.abc不会返回p内部的abc变量。这一点跟高级编程语言完全一致,你无法在类外部访问其private变量,但是我们可以借助public方法来返回私有变量。所以高级编程语言如java,c#等中属性的作用,就是保护私有变量。像c#这门语言,属性最终会由编译器编译为get_属性名()这样的方法,当我们使用某个属性时,实质上是调用一个方法。

使用面向对象的技术创建高级 web 应用程序》的作者认为是由于方法的定义才使局部变量存活下来,这一点是不正确的,具体我们前面已经分析过了,如果你仍有疑问,那么再仔细研究下面的代码:

function person(name, age) {

this.getname = function() {debugger; return 1; };

}

var o = new person(1,2);

o.getname();// 进入调试后发现name=1

var t = new person(2,4);

t.getname();// 进入调试后发现name=2

o.getname();// 进入调试后发现name=1,并未受到其它实例的影响

对于这个问题,我起初也认为是因为变量有引用才没被销毁,最后证明局部变量在对象销毁前其内部的变量不会销毁。

同时那篇文章中另外一段也是不准确的:

注意,这些私有成员与我们期望从 c# 中产生的私有成员略有不同。在 c# 中,类的公用方法可以访问它的私有成员。但在 javascript 中,只能通过在其闭包内拥有这些私有成员的方法来访问私有成员(由于这些方法不同于普通的公用方法,它们通常被称为特权方法)。因此,在 person 的公用方法中,仍然必须通过私有成员的特权访问器方法才能访问私有成员

关于这一点,他的表述相当模糊,事实上我们可以这样理解:

在c#中我们可以在类的任何方法中访问类的私有成员变量,

而在javascript中,只能使用在function方式中定义的方法对私有成员访问,而无法在prototype方式定义的方法中访问。

如果这样讲你还不能理解的话,那么还可以这样理解,在javascript中的私有变量无法在其声明函数外访问,例如:

function person()

{

var ttt;

}

永远不能在{}外部试图访问ttt。

现在我们更加深入的理解了变量作用域在javascript中的特点。

前面讲了高级编程语言中属性的种种好处,又研究了javascript对私有变量的保护,那么您对javascript中属性的实现应该非常清楚了,这里引用《使用面向对象的技术创建高级 web 应用程序》文中的一段示例代码:

function person(name, age) {

this.getname = function() { return name; };

this.setname = function(newname) { name = newname; };

this.getage = function() { return age; };

this.setage = function(newage) { age = newage; };

}

关于属性在实际中的应用及其优点,将在我下一篇文章介绍自定义事件中讲解。

后记:本来打算在这里讲述如何在javascript中实现面向对象中的一些特性,比如用“属性”这一现代编程概念体现的对象的封装性:不直接操作类的数据内容,而是通过访问器进行访问,即借助于get和set对私有成员的值进行读写。最后却演变成为一个白马是不是马的哲学讨论,真是汗颜。

原创粉丝点击