对象是JS的基本数据类型。对象是一种复合值,它将很多值聚合在一起,可通过名字访问这些值。对象也可看作是属性的无序集合,每个属性都是一个 名/值 对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。除了可以保持自有的属性,JS还可以从一个称为原型的对象继承属性。
除了字符串,数字,true, false, null, undefined之外,JS中的值都是对象。
对象最常见的用法是创建,设置,查找,删除,检测和枚举它的属性。
属性包括名字和值。属性名可以是包含空字符串在内的任意字符串,但对象中不能存在两个同名的属性。值可以是任意JS值,或者是一个getter或setter函数。
除了名字和值之外,每个属性还有一些与之相关的值,称为“属性特性”:
- 可写 —— 表明是否可以设置该属性的值
- 可枚举 —— 表明是否可以通过for/in循环返回该属性
- 可配置 —— 表明是否可以删除或修改该属性
除了包含属性之外,每个对象还拥有三个相关的对象特性:
- 对象的原型(prototype)—— 指向另外一个对象,本对象的属性继承自它的原型对象
- 对象的类(class)—— 是一个标识对象类型的字符串
- 对象的扩展标记(extensible flag)—— 指明了是否可以向该对象添加新属性
三类JavaScript对象:
- 内置对象(native object)—— 是由ECMAScript规范定义的对象或类。例如,数组,函数,日期和正则表达式都是内置对象
- 宿主对象(host object)—— 是由JS解释器所潜入的宿主环境定义的(如浏览器)。
- 自定义对象 —— 是由运行中的JS代码创建的对象
两类属性:
- 自有属性 —— 是直接在对象中定义的属性
- 继承属性 —— 是在对象的原型对象中定义的属性
创建对象
可以通过对象直接量,关键字new 和Object.create()函数来创建对象。
对象直接量创建对象
创建对象最简单的方式就是在JavaScript代码中使用对象直接量。
对象直接量是由若干名/值对组成的映射表,名/值对 中间用冒号分隔,名/值对 之间用逗号分隔,整个映射表用花括号括起来。
例如:
var empty = {};
var point = (x:0, y:0);
var book = {
"main title":"JavaScript",
"sub-title":"The Definitive Guide",
author : { // 这里的属性名没有引号
first:"David",
surname:"Flanagan"
}
}
对象直接量是一个表达式,这个表达式的每次运算都创建并初始化一个新的对象。
原型(对象直接量的原型)
每一个JS对象都和另一个对象相关联,即原型,每一个对象都从原型继承属性。
所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JS代码Object.prototype获得对原型对象的引用。
通过new 创建对象
关键字 new 后跟着一个函数调用,这里的函数称作 构造函数,构造函数用以初始化一个新创建的对象。
JS语言核心中的原始类型都包含内置构造函数。
例如:
var o = new Object(); // 创建一个空对象,和{}一样
var a = new Array(); // 创建一个空数组,和[]一样
Object.create()
Object.create()是一个静态函数,第一个参数是这个对象的原型,第二个参数可选,用以对对象的属性进一步描述。
例如:
var o1 = Object.create({x:1, y:2}); // o1继承了属性x 和 y
var o3 = Object.create(Object.prototype); // o3和{}和new Object()一样
对象属性的查询和设置
可以通过点(.)和方括号([])运算符获取属性的值。
例如:
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"属性赋值
查询一个不存在的属性并不会报错,如果在对象滋生的属性或继承的属性中均为找到属性,属性的访问表达式返回undefined。
但是,如果对象不存在,那么视图查询这个不存在的对象的属性就会报错。
删除对象属性
delete 运算符可以删除对象的属性。
它的操作数应当是一个属性访问表达式。delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。
例如:
delete book.author;
delete book["main title"];
delete运算符只能删除自有属性,不能删除继承属性。
delete不能删除那些可配置性为false的属性
检测对象属性
经常要判断某个属性是否存在与某个对象中。
可以通过in运算符,hasOwnProperty()和propertyIsEnumerable()方法来完成这个工作,甚至仅通过属性查询也可以。
- in运算符 —— 左侧是属性名,右侧是对象,如果对象的自有属性或继承属性中包含这个属性则返回true。
例如:
var o = {x:1}
"x" in o; // true
"y" in o; // true
"toString" in o // true, o 继承toString属性
- 对象的hasOwnProperty()方法 —— 用来检测给定的名字是否是对象的自有属性,对于继承属性它将返回false;
例如:
var o = {x:1}
o.hasOwnProperty("x"); // true
o.hasOwnProperty("y"); // false
o.hasOwnProperty("toString"); // false;继承属性
- propertyIsEnumerable()方法 —— 是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性的可枚举性为true时它才返回true。
- 除了使用in 运算符之外,另一种更简便的方法是使用“!==”判断一个属性是否是undefined。!==可以区分undefined和null
例如:
var o = {x:1}
o.x !== undefined; // true
o.y !== undefined; // false
o.toString !== undefined; // true
枚举对象属性
- for/in循环,例如:
var o = {x:1, y:2,z:3};
for (p in o)
console.log(p); // 输出x,y,z
- 函数Object.keys()
- 函数Object.getOwnPropertyNames()
属性getter和setter
对象的三个属性
每个对象都有与之相关的原型,类,和可扩展性。
原型属性
对象的原型属性是用来继承属性的。
原型属性是在实例对象创建之初就设置好的:
- 通过对象直接量创建的对象使用Object.prototype作为它们的原型
- 通过new创建的对象使用构造函数的prototype属性作为它们的原型
- 通过Object.create()创建的对象使用第一个参数作为它们的原型
要想检测一个对象是否是另一个对象的原型,使用isPrototypeOf()方法:
var p = {x:1};
var o = Object.create(p);
p.isPrototypeOf(o); //=> true
类属性
对象的类属性是一个字符串,用以表示对象的类型信息。
- 通过内置构造函数(Array和Date)创建的对象包含“类属性”,它与构造函数名称相匹配
- 通过对象直接量和Object.create()创建的对象的类属性是“Object”
- 那些自定义构造函数创建的对象也是一样,类属性也是“Object”
可扩展性
对象的可扩展性用以表示是否可以给对象添加新属性。
序列化对象
对象序列化是指将对象的状态转换为字符串,也可以将字符串还原为对象。
ECMAScript提供了内置函数JSON.stringify()和JSON.parse()来序列化和还原JS对象。这些方法都适用JSON作为数据交换格式。
例如:
o = {x:1, y:{z:[false,null,""]}};
s = JSON.stringify(o); // s是 '{"x":1,"y":{"z":[false,null,""]}}'
p = JSON.parse(s);
对象方法
所有的JS对象都从 Object.prototype继承属性,这些属性主要是方法。
toString()方法
toString()方法没有参数,它将返回一个表示调用这个方法的对象值的字符串。
在需要将对象转换为字符串的时候,JS都会调用这个方法。
很多类都带有自定义的toString()方法。
toLocaleString()方法
这个方法返回一个表示这个对象的本地化字符串。Object中默认的该方法并不做任何本地化自身的操作,它仅调用toString()方法并返回对应值。
toJSON()方法
Object.prototype实际上没有定义toJSON()方法,但对于需要执行序列化的对象来说,JSON.stringify()方法会调用toJSON()方法。
valueOf()方法
当JS需要将对象转换为某种原始值而非字符串的时候才会调用它,尤其是转换为数字的时候。