对象:
我们先对JavaScript的三类对象和两类属性做区分:
- 内置对象(native object):是由ECMAScript规范定义的对象或类。例如:数组、函数、日期和正则表达式都是内置对象。
- 宿主对象(host object):是由Javascript解释器所嵌入的宿主环境(比如Web浏览器)定义的。客户端JavaScript中表示网页结构的HTMLElement对象均是宿主对象。既然宿主环境定义的方法可以当成普通的JavaScript函数对象,那么宿主对象也可以当成是内置对象。
- 自定义对象(user-defined object):是由运行中的JavaScript代码创建的对象。
- 自有属性(own property):是直接在对象中定义的属性。
- 继承属性(inherited property):是在对象的原型对象中定义的属性。
创建对象:
- 对象直接量:是由若干名/值对组成的映射表,名/值对中间用冒号分隔,名/值对之间用逗号分隔,整个映射表用花括号括起来。
var empty = { }; //没有任何属性的对象 var point = { x:0, y:0 }; //两个属性 var point2 = { x:point.x, y:point.y+1 }; //更复杂的值 var book = { "main title": "JavaScript", //属性名字里有空格,必须用字符串表示 "sub-title": "The Definitive Guide", //属性名字里有连字符,必须用字符串表示 "for": "all audiences", //“for”是保留字,因此必须用引号 author: { //这个属性的值是一个对象 firstname: "David", //注意,这里的属性名都没有引号 lastname: "Flanagan" } };
- 通过new创建对象:关键字new后跟随一个函数调用。这里的函数称作构造函数(constructor),构造函数用以初始化一个新创建的对象。
var o = new Object(); //创建一个空对象,和{}一样 var a = new Array(); //创建一个空数组,和[]一样 var d = new Date(); //创建一个表示当前时间的Date对象 var r = new RegExp("js"); //创建一个可以进行模式匹配的RegExp对象
- Object.create():用于创建一个新对象,其中第一个参数是这个对象的原型。Onject.create()提供第二个可选参数,用以对对象的属性进行进一步的描述。后面会详细讲第二个参数。Object.create()是一个静态函数,而不是提供某个对象调用的方法。
var o1 = Object.create({x:1, y:2}); //o1继承了属性x和y var o2 = Object.create(null); //o2不继承任何属性和方法 var o3 = Object.create(object.prototype); //o3是一个普通的空对象,和{}或new object()一样 /*Object.create()可以通过任意原型创建新对象,换句话说,可以使任意对象可继承,这是一个强大的特性。*/ //inherit()返回了一个继承自原型对象p的属性的新对象 //这里使用ECMAScript 5中的Object.create()函数(如果存在的话) //如果不存在Object.create(),则退化使用其他方法 function inherit(p) { if(p == null) throw TypeError(); //p是个继承对象,但不能是null if(Object.create) //如果Object.create()存在 return Object.create(p); //直接使用它 var t = typeof(p); //否则进行进一步检测 if( t !== "object" && t !== "function") throw TypeError(); function f() { }; //定义一个空构造函数 f.prototype = p; //将其原型属性设置为p return new f(); //使用f()创建p的继承对象 }
属性的查询和设置:
可以通过点(.)或方括号([])运算符获得属性的值。运算符左侧应当是一个表达式,它返回一个对象。
- 对于点(.)来说,右侧必须是一个以属性名称命名的简短标识符。
- 对于方括号([])来说,方括号内必须是一个计算结果为字符串的表达式,这个字符串就是属性的名字。
var author = book.author; //得到book的“author”属性
var name = author.surname; //得到获得author的“surname”属性
var title = book["main title"]; //得到book的“main title”属性
和查询属性值的写法一样,通过点和方括号也可以创建属性或给属性赋值,但需要将它们放在赋值表达式的左侧
book.edition = 6; //给book创建一个名为“edition”的属性
book["main title"] = "ECMAScript"; //给“main title”属性赋值
*在ECMAScript 3中,点运算符后的标识符不能是保留字,比如,o.for或o.class是非法的,想要访问这些保留字,必须使用方括号的形式访问他们:o["for"]、o["class"]。
*ECMAScript 5对此放宽了限度(包括ECMAScript 3的某些实现),可以在点运算符后直接使用保留字。
作为关联数组的对象:
object.prototype 和 object["prototype"]这两个表达式的值相同。
第一种语法使用点运算和一个标识符,这个C和Java中访问一个结构体或对象的静态字段非常相似。
第二种语法使用方括号和一个字符串,看起来更像数组,只是这个数组元素是通过字符串索引而不是数字索引。
这种数组就是我们所说的关联数组(associative array),也称为散列、映射或字典(dictionary)。JavaScript对象都是关联数组。我个人比较倾向关联数组:通过[ ]来访问对象的属性时,属性名通过字符串来表示。字符串是JavaScript的数据类型,所以在程序运行时可以修改和创建它们。
var addr = "";
for (i=0; i<4; i++) {
addr += customer["address"+i]+'\n';
}//这段代码读取customer对象的address0、address1、address2和address3属性,并将它们连接起来
这个例子主要说明,使用数组写法和应用字符串表达式来访问对象属性的灵活性。
*字符串是动态的,可以在运行时更改,而标识符是静态的,必须写死在程序中。