3.9 对象

必备知识:前面课程的学习

本章是难点章节,主要有以下几个部分:

  • 对象
  • 属性
  • 对象的创建
  • 方法
  • 通过 this 引用对象

对象

JavaScript 采用了简单的基于对象的范型。一个对象就是一系列属性的集合,一个属性包含一个名字和一个值。一个属性的值可以是函数,这种情况下属性也被称为方法。除了浏览器里面预定义的那些对象之外,你也可以定义你自己的对象。本章节讲述了怎么使用对象、属性、函数和方法,怎样实现自定义对象。

JavaScript 中的对象(物体),和其它编程语言中的对象一样,可以比照现实生活中的对象(物体)来理解它。 JavaScript 中对象(物体)的概念可以比照着现实生活中实实在在的物体来理解。

在 ,JavaScript 中,一个对象可以是一个单独的拥有属性和类型的实体。我们拿它和一个杯子做下类比。一个杯子是一个对象(物体),JavaScript 对象也有属性来定义它的特征。

属性

一个 ,JavaScript 对象有很多属性。一个对象的属性可以被解释成一个附加到对象上的变量。对象的属性和普通的 ,JavaScript 变量基本没什么区别,仅仅是属性属于某个对象。属性定义了对象的特征,你可以通过点符号来访问一个对象的属性。

objectName.propertyName

和其他 ,JavaScript 变量一样,对象的名字(可以是普通的变量)和属性的名字都是大小写敏感的。你可以在定义一个属性的时候就给它赋值。例如,我们创建一个 myCar 的对象然后给他三个属性,make,model,year。具体如下所示:

var myCar = new Object();
myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969;

注:对象中未赋值的属性的值为 undefined(而不是 null)。

JavaScript 对象的属性也可以通过方括号访问或者设置(更多信息查看 property accessors)。对象有时也被叫作关联数组,因为每个属性都有一个用于访问它的字符串值。例如,你可以按如下方式访问 myCar 对象的属性:

myCar["make"] = "Ford";
myCar["model"] = "Mustang";
myCar["year"] = 1969;

一个对象的属性名可以是任何有效的 JavaScript 字符串,,或者可以被转换为字符串的任何类型,包括空字符串。然而,一个属性的名称如果不是一个有效的 JavaScript 标识符(例如,一个由空格或连字符,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。例如:

var myObj = new Object(),
    str = "myString",
    rand = Math.random(),
    obj = new Object();

myObj.type              = "Dot syntax";
myObj["date created"]   = "String with space";
myObj[str]              = "String value";
myObj[rand]             = "Random Number";
myObj[obj]              = "Object";
myObj[""]               = "Even an empty string";

console.log(myObj);

你也可以通过存储在变量中的字符串来访问属性:

var propertyName = "make";
myCar[propertyName] = "Ford";

propertyName = "model";
myCar[propertyName] = "Mustang";

你可以在 for...in 语句中使用方括号标记以枚举一个对象的所有属性。为了展示它如何工作,下面的函数当你将对象及其名称作为参数传入时,显示对象的属性:

function showProps(obj, objName) {
  var result = "";
  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
        result += objName + "." + i + " = " + obj[i] + "\n";
    }
  }
  return result;
}

因而,对于函数调用showProps(myCar, "myCar")将返回以下值:

myCar.make = Ford
myCar.model = Mustang
myCar.year = 1969

对象的创建

使用对象初始化器创建对象

除了通过构造函数创建对象之外,你也可以通过对象初始化器创建对象。使用对象初始化器也被称作通过字面值创建对象。对象初始化器与 C++ 术语相一致。

通过对象初始化器创建对象的语法如下:

var obj = { property_1:   value_1,   // property_# may be an identifier...
            2:            value_2,   // or a number...
            // ...,
            "property n": value_n }; // or a string

这里 obj 是新对象的名称,每一个 property_i 是一个标识符(可以是一个名称、数字或字符串字面量),并且每个 value_i 是一个其值将被赋予 property_i 的表达式。obj 与赋值是可选的;如果你不需要在其他地方引用对象,你就不需要将它赋给一个变量。

下面的语句只有当 cond 表达式的值为 true 时创建对象并将其赋给变量 x:

if (cond) var x = {hi: "there"};

下例创建了有三个属性的 myHonda 对象,注意它的 engine 属性也是一个拥有自己属性的对象:

var myHonda = {color: "red", wheels: 4, engine: {cylinders: 4, size: 2.2}};

使用构造函数创建对象

作为另一种方式,你可以通过两步来创建对象:

  1. 通过创建一个构造函数来定义对象的类型,首字母大写是非常普遍而且很恰当的惯用法。
  2. 通过 new 创建对象实例。

为了定义对象类型,为对象类型创建一个函数以声明类型的名称、属性和方法。例如,你想为汽车创建一个类型,并且将这类对象称为 car ,并且拥有属性 make, model, 和 year,你可以创建如下的函数:

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

注:我们通过使用 this 关键字将传入函数的值赋给对象的属性。

现在你可以象这样创建一个 mycar 对象:

var mycar = new Car("Eagle", "Talon TSi", 1993);

该创建了 mycar 并且将指定的值赋给它的属性。因而 mycar.make 的值是字符串 "Eagle", mycar.year 的值是整数 1993,依此类推。

你可以通过调用 new 创建任意数量的 car 对象。例如:

var kenscar = new Car("Nissan", "300ZX", 1992);
var vpgscar = new Car("Mazda", "Miata", 1990);

一个对象的属性值可以是另一个对象。例如,假设你按如下方式定义了 person 对象:

function Person(name, age, sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
}

然后按如下方式创建了两个 person 实例:

var rand = new Person("Rand McKinnon", 33, "M");
var ken = new Person("Ken Jones", 39, "M");

那么,你可以重写 car 的定义以包含一个拥有它的 owner 属性,如:

function Car(make, model, year, owner) {
  this.make = make;
  this.model = model;
  this.year = year;
  this.owner = owner;
}

你可以按如下方式创建新对象:

var car1 = new Car("Eagle", "Talon TSi", 1993, rand);
var car2 = new Car("Nissan", "300ZX", 1992, ken);

注意在创建新对象时,上面的语句将 rand 和 ken 作为 owner 的参数值,而不是传入字符串字面量或整数值。接下来你如果想找出 car2 的拥有者的姓名,你可以访问如下属性:

car2.owner.name

你总是可以为之前定义的对象增加新的属性。例如,

car1.color = "black";

为 car1 增加了 color 属性,并将其值设为 "black" 然而,这并不影响其他的对象。想要为某个类型的所有对象增加新属性,你必须将属性加入到 car 对象类型的定义中。

补充:为对象类型定义属性

你可以通过 prototype 属性为之前定义的对象类型增加属性。这为该类型的所有对象,而不是仅仅一个对象增加了一个属性。下面的代码为所有类型为 car 的对象增加了 color 属性,然后为对象 car1 的 color 属性赋值:

Car.prototype.color = null;
car1.color = "black";

方法

为对象定义方法

一个方法是关联到某个对象的函数,或者简单地说,一个方法是一个值为某个函数的对象属性。定义方法就像定义普通的函数,除了它们必须被赋给对象的某个属性。

objectName.methodname = function_name;

var myObj = {
  myMethod: function(params) {
    // ...do something
  }
};

这里 objectName 是一个已经存在的对象,methodname 是方法的名称,而 function_name 是函数的名称。

你可以在对象的上下文中象这样调用方法:

object.methodname(params);

你可以在对象的构造函数中包含方法定义来为某个对象类型定义方法。例如,你可以为之前定义的 car 对象定义一个函数格式化并显示其属性:

function displayCar() {
  var result = "A Beautiful " + this.year + " " + this.make
    + " " + this.model;
  pretty_print(result);
}

这里 pretty_print 是一个显示横线和一个字符串的函数。注意使用 this 指代方法所属的对象。

你可以在对象定义中通过增加下述语句将这个函数变成 car 的方法:

this.displayCar = displayCar;

因此,car 的完整定义看上去将是:

function Car(make, model, year, owner) {
  this.make = make;
  this.model = model;
  this.year = year;
  this.owner = owner;
  this.displayCar = displayCar;
}

按如下方式为每个对象调用 displayCar 方法:

car1.displayCar();  // A Beautiful 1993 Eagle Talon TSi
car2.displayCar();  // A Beautiful 1992 Nissan 300ZX

通过 this 引用对象

JavaScript 有一个特殊的关键字 this,它可以在方法中使用以指代当前对象。例如,假设你有一个名为 validate 的函数,它根据给出的最大与最小值检查某个对象的 value 属性:

function validate(obj, lowval, hival) {
  if ((obj.value < lowval) || (obj.value > hival))
    alert("Invalid Value!");
}

然后,你可以在每个元素的 onchange 事件处理器中调用 validate,并通过 this 传入相应元素,代码如下:

<input type="text" name="age" size="3" onChange="validate(this, 18, 99)">

总的说来, this 在一个方法中指调用的对象。

当与 form 属性一起使用时,this 可以指代当前对象的父窗体。在下面的例子中,窗体 myForm 包含一个 Text 对象和一个按钮,当用户点击按键,Text 对象的值被设为窗体的名称。按钮的 onclick 事件处理器使用 this.form 以指代其父窗体,即 myForm。

<form name="myForm">
<p><label>Form name:<input type="text" name="text1" value="Beluga"></label>
<p><input name="button1" type="button" value="Show Form Name"
     onclick="this.form.text1.value = this.form.name">
</p>
</form>

类和对象是面向对象语言的经典话题,关于对象的知识,未来在介绍 python 的时候会有更加详细的阐述。

本节任务

results matching ""

    No results matching ""