六、JavaScript 对象

JavaScript 对象是 JavaScript 编程语言如此通用的原因。在深入研究数据结构和算法之前,让我们回顾一下 JavaScript 对象是如何工作的。本章将关注什么是 JavaScript 对象,如何声明它们,以及如何改变它们的属性。此外,本章将介绍如何使用原型继承实现 JavaScript 类。

JavaScript 对象属性

JavaScript 对象可以通过对象字面量{}或语法 new Object();来创建。可以通过两种方式添加或访问附加属性:object.propertyNameobject['propertyName']

1   var javaScriptObject = {};
2   var testArray = [1,2,3,4];
3
4   javaScriptObject.array = testArray;
5   console.log(javaScriptObject); // {array: [1,2,3,4]}
6
7   javaScriptObject.title = 'Algorithms';
8   console.log(javaScriptObject); // {array: [1,2,3,4], title:'Algorithms'}

如前面的代码所示,title属性在第 7 行被动态添加到 JavaScript 对象中。类似地,JavaScript 类中的函数也是通过动态添加到对象中来添加的。

原型遗传

在大多数强类型语言(如 Java)中,类的方法是与类同时定义的。然而,在 JavaScript 中,该函数必须作为该类的 JavaScript Object属性添加。

下面是一个使用this.functionName = function(){}的 JavaScript 类的例子:

 1   function ExampleClass(){
 2       this.name = "JavaScript";
 3       this.sayName = function(){
 4           console.log(this.name);
 5       }
 6   }
 7
 8   //new object
 9   var example1 = new ExampleClass();
10   example1.sayName(); //"JavaScript"

这个类在构造函数中动态添加了sayName函数。这种模式被称为原型遗传

原型继承是 JavaScript 中唯一的继承方法。要添加一个类的函数,只需使用.prototype属性并指定函数名。

当您使用.prototype属性时,您实际上是在动态扩展对象的 JavaScript Object属性。这是标准的,因为 JavaScript 是动态的,类可以在以后需要时添加新的函数成员。这对于 Java 等编译语言来说是不可能的,因为它们会在编译时抛出错误。JavaScript 的这个独特属性让开发人员可以利用原型继承。

这里有一个使用.prototype的例子:

 1   function ExampleClass(){
 2       this.array = [1,2,3,4,5];
 3       this.name = "JavaScript";
 4   }
 5
 6   //new object
 7   var example1 = new ExampleClass();
 8
 9   ExampleClass.prototype.sayName = function() {
10       console.log(this.name);
11   }
12
13   example1.sayName(); //"JavaScript"

重申一下,动态地向类添加函数是 JavaScript 实现原型继承的方式。类的函数要么在构造函数中添加,要么通过.prototype添加。

构造函数和变量

因为 JavaScript 中一个类的变量是该类对象的属性,所以任何用this.propertyName声明的属性都是公开可用的。这意味着可以在其他范围内直接访问对象的属性。

 1   function ExampleClass(name, size){
 2       this.name = name;
 3       this.size = size;
 4   }
 5
 6   var example = new ExampleClass("Public",5);
 7   console.log(example); // {name:"Public", size: 5}
 8
 9   // accessing public variables
10   console.log(example.name); // "Public"
11   console.log(example.size); // 5

为了模仿私有变量,而不是使用this.propertyName,您可以声明一个局部变量,并让 getter/setter 允许访问该变量。这样,变量只对构造函数的作用域可用。然而,值得注意的是,这些被模仿的私有变量现在只能通过定义的接口函数(getter getName和 setter setName)来访问。这些 getters 和 setters 不能添加到构造函数之外。

 1   function ExampleClass(name, size) {
 2       var privateName = name;
 3       var privateSize = size;
 4
 5       this.getName = function() {return privateName;}
 6       this.setName = function(name) {privateName = name;}
 7
 8       this.getSize = function() {return privateSize;}
 9       this.setSize = function(size) {privateSize = size;}
10   }
11
12   var example = new ExampleClass("Sammie",3);

13   example.setSize(12);
14   console.log(example.privateName); // undefined
15   console.log(example.getName()); // "Sammie"
16   console.log(example.size); // undefined
17   console.log(example.getSize()); // 3

摘要

在 JavaScript 中,与其他面向对象的编程语言不同,原型继承是首选的继承方法。原型继承通过.prototype向 JavaScript 类添加新函数来工作。在 Java 和 C++中,私有变量是显式声明的。然而,JavaScript 不支持私有变量,为了模仿私有变量的功能,您需要创建一个作用于构造函数的变量。通过this.variableName在构造函数中将变量声明为该对象的一部分会自动使该属性成为公共属性。

练习

向对象添加属性

以两种不同的方式向一个空的 JavaScript 对象添加一个exampleKey属性,并将其设置为exampleValue

正如本章前面所讨论的,可以通过两种方式将属性添加到对象中。使用一种方法比使用另一种方法没有性能优势或劣势;选择归结于风格。

 1   var emptyJSObj = {};
 2   emptyJSObj['exampleKey'] = 'exampleValue';
 3   emptyJSObj.exampleKey = 'exampleValue';

定义类别

创建两个类:AnimalDogAnimal类应该在构造函数中接受两个参数(nameanimalType)。将它们设置为它的公共属性。

另外,Animal类应该有两个函数:sayNamesayAnimalTypesayName打印namesayAnimalType打印在构造函数中初始化的animalType

最后,Dog类继承了Animal类。

  1. 让我们首先定义Animal类和指定的所需函数。

  2. 为了让Dog类继承它,定义Dog类,然后复制它的原型,如下面的代码块所示:

 1   function Animal(name, animalType) {
 2       this.name = name;
 3       this.animalType = animalType;
 4   }
 5   Animal.prototype.sayName = function () {
 6       console.log(this.name);
 7   }
 8   Animal.prototype.sayAnimalType  = function () {
 9       console.log(this.animalType);
10   }
 1   function Dog(name) {
 2       Animal.call(this, name, "Dog");
 3   }
 4   // copy over the methods
 5   Dog.prototype = Object.create(Animal.prototype);
 6   var myAnimal = new Animal("ditto", "pokemon");
 7   myAnimal.sayName(); // "ditto"
 8   myAnimal.sayAnimalType(); // "pokemon"
 9   var myDog = new Dog("candy", "dog");
10   myDog.sayName(); // "candy"
11   myDog.sayAnimalType(); // "dog"