面向对象的JavaScript基本知识指南大全(1)(2)
确保属性值的私有性
请注意:在前一个例子中,我们只要调用bob.age,就能获得bob.age的值。此外,我们可以在程序中任何地方将bob.age设成自己喜欢的任何值。
- var bob = new Student("bob", "male", 15, 10, "Marlow");
- alert(bob.age); //输出15
- bob.age = 9;
- alert(bob.age); //输出9;
看起来没有害处,是不是?那么请考虑这个例子。
- var bob = new Student("bob", "male", 15, 10, "Marlow");
- alert(bob.age); //输出15
- bob.age = -50;
- alert(bob.age); //输出-50;
我们看到了年龄是负值:这在逻辑上不一致。我们只要使用私有变量(private variable)这个概念,就可以防止诸如此类的问题、确保数据的完整性。私有变量是只能在类本身里面访问的变量。虽然JavaScript再次没有用于确保变量私有性的保留字,但是JavaScript为我们提供了创造同样效果的工具。
- function Student(name, gender, age, grade, teacher)
- {
- var studentName = name;
- var studentGender = gender;
- var studentGrade = grade;
- var studentTeacher = teacher;
- var studentAge = age;
- this.getAge = function()
- {
- return studentAge;
- };
- this.setAge = function(val)
- {
- studentAge = Math.abs(val); //使用绝对值,确保年龄是正值
- };
- }
- var bob = new Student("bob", "male", 15, 10, "Marlow");
- alert(bob.studentAge); //未定义,因为年龄在类定义中受私有保护
- alert(bob.getAge()); //输出15
- bob.setAge(-20);
- alert(bob.getAge()); //输出20
通过使用变量声明,而不是直接为类赋予属性,我们保护了年龄数据的完整性。由于JavaScript使用了函数范围,我们的类里面声明的变量在该类外面是无法访问的,除非由该类里面的函数明确返回。方法this.getAge将学生年龄返回到调用环境,它名为访问器方法(Accessor method)。访问器方法返回属性的值,那样该值就可以在类的外面使用,而不影响类里面的值。按照约定,访问器方法的前缀通常是“get”这个字。方法this.setAge名为更改器方法(Mutator method)。其目的是,改变属性的值,保护完整性。
我们已看到了在类里面使用访问器方法和更改器方法来保护数据完整性的好处。不过,为每个属性创建访问器方法带来了极其冗长的代码。
- function Student(name, gender, age, grade, teacher)
- {
- var studentName = name;
- var studentGender = gender;
- var studentGrade = grade;
- var studentTeacher = teacher;
- var studentAge = age;
- this.getName = function()
- {
- return studentName;
- };
- this.getGender = function()
- {
- return studentGender;
- };
- this.getGrade = function()
- {
- return studentGrade;
- };
- this.getTeacher = function()
- {
- return studentTeacher;
- };
- this.getAge = function()
- {
- return studentAge;
- };
- this.setAge = function(val)
- {
- studentAge = Math.abs(val); //使用绝对值,确保年龄是正值
- };
- }
- var bob = new Student("bob", "male", 15, 10, "Marlow");
- alert(bob.studentGender); //未定义,因为性别在类定义中受私有保护
- alert(bob.getGender()); //输出 'male'
教我C++的教授总是说:“如果你发现自己反复输入相同的代码,这表明你的做法不对。”的确,有更高效的方法可以为每个属性创建访问器方法。此外,这种机制还不需要以特定次序来调用函数参数。
动态创建的访问器方法
这个演示来自John Resig所写的《专业JavaScript技巧》一书(我强烈建议各位读一读。前三章就非常值得一读)。
- function Student( properties )
- {
- var $this = this; //将类范围存储到名为$this的变量中
- //迭代处理对象的属性
- for ( var i in properties )
- {
- (function(i)
- {
- // 动态创建访问器方法
- $this[ "get" + i ] = function()
- {
- return properties[i];
- };
- })(i);
- }
- }
- // 创建一个新的用户对象实例,并传递属性的对象
- var student = new Student(
- {
- Name: "Bob",
- Age: 15,
- Gender: "male"
- });
- alert(student.name); //因属性是私有的而未定义
- alert(student.getName()); //输出 "Bob"
- alert(student.getAge()); //输出15
- alert(student.getGender()); //输出 "male"
通过实施这个技巧,我们不但确保自己的属性是私有的,而且不需要按次序来指定参数。下面的类实例化都相同:
- var student = new Student(
- {
- Name: "Bob",
- Age: 15,
- Gender: "male"
- });
- var student = new Student(
- {
- Age: 15,
- Name: "Bob",
- Gender: "male"
- });
- var student = new Student(
- {
- Gender: "male",
- Age: 15,
- Name: "Bob"
- });
<< 上一页 1 23 下一页>>