模拟私有属性
现在介绍闭包如何帮助模拟私有成员。正常情况下,无法从函数以外访问函数内的本地变量。函数退出之后,由于各种实际的原因,该本地变量将永远消失。但是,如果该本地变量被内部函数的闭包捕获,它将生存下来。这一事实是模拟JavaScript私有属性的关键。假设有一个Persion类:
function Persion(name, age) { this.getName = function(){return name;}; this.setName = function(newName){name = newName;}; this.getAge = function(){return age;}; this.setAge = function(newAge){age = newAge;}; }
参数name和age是构造函数Persion的本地变量。Persion返回时,name和age应当永久消失。但是,它们被作为Persion实例的方法而分配的四个内部函数捕获,实际上这会使name和age继续存在,但只能严格地通过这四个方法访问它们。因此,您可以:
var ray = new Persion('Ray', 31); alert(ray.getName()); alert(ray.getAge()); ray.setName("Younger Ray"); //Instant rejuvenation ray.setAge(22); alert(ray.getName() + " is now " + ray.getAge() + "years old.");
未在构造函数中初始化的私有成员可以成为构造函数的本地变量,如下所示:
function Persion(name, age) { var occupation; this.getOccupation = function() //accessors for name and age { return occupation; } this.setOccupation = function(newOcc) { occupation = newOcc; } }
注意,这些私有成员与我们期望从C#中产生的私有成员略有不同,在C#中,类的公用方法可以访问它的私有成员。但是在JavaScript中,只能通过在其闭包内拥有这些私有成员的方法来访问成员(由于这些方法不同于普通的公用方法,它们通常被称为特权方法),因此,在Persion的公用方法中,仍然必须通过私有成员的特权访问器方法才能访问私有成员:
Persion.prototype.somePublicMethod = function() { // doesn't work! // alert(this.name); // this one below works alert(this.getName); }
Douglas Crockford 是著名的发现(或者也许是发布)使用闭包来模拟私有成员这一技术的第一人。他的网站 javascript.crockford.com 包含有关 JavaScript 的丰富信息,任何对 JavaScript 感兴趣的开发人员都应当仔细研读。
下一节:从类继承