创建对象
可以通过对象直接量或者构造函数来创建对象,此外ECMA 5还规定了一种方法
Object.create(),第一个参数为对象的原型,第二个可选参数用来对对象的属性进行进一步描述。
如果第一个参数传入null,则对象不继承任何东西,连最基础的例如toString()也没有,因此想创建一个普通空对象,可以传入参数Object.prototype。为了防止代码无意间修改不受控制的对象A,可以将继承了A的对象B传入,而不是直接传入A,这样,当修改B的属性,如果修改的是原型属性,实际上是已经创建的了一个同名的实例属性,屏蔽了原型属性。防止了修改A中的属性,除非这是一个引用类型的属性。例如下面的代码:
function inherit(p) {
if (p == null) {
throw TypeError();
}
if (Object.create) {
return Object.create(p);
}
var t = typeof p;
if (t != "object" && t != "function") {
throw TypeError();
}
function f() {};
f.prototype = p;
return new f();
}
var o = {blabla...};
func(inherit(o));
属性访问
有两种方式:. 和[]。
前者属性名必须是确定的;而后者传入一个字符串,在运行时可以动态修改,例如当访问的属性名需要通过传入函数的参数来确定,则必须采用[]的访问方式;或者属性名是在程序运行过程中动态生成的,也需采用[]的方式。
使用[]方式访问对象属性,实际上是把对象看作关联数组。访问对象不存在的属性不会报错,返回undefined;但访问不存在的对象的属性则会报错,因为null和undefined是没有属性的。因此有时需要谨慎访问对象的属性,需要在访问前用if判断对象是否存在,或采用如下更简洁的方式:
var len = book && book.subtitle && book.subtitle.length;
枚举属性
for in
遍历对象中所有可枚举的属性(包括自有和继承的属性)。
Object.keys()
返回所有的可枚举的自有属性名称组成的数组。ES5提供。
Object.getOwnPropertyName()
返回所有自有属性的名称组成的数组,包括可枚举和不可枚举的。ES5提供。
删除属性
delete运算符只能删除自由属性,不能删除继承的属性。且需注意一个对象是否有其他的引用, 在删除的时候可能没有删除干净。
delete用于删除对象属性或数组元素,但一些内置对象的属性不能删除,此外,通过 var声明的变量和生命的function也不能删除,即便使用window.XX or this.XX的方式也不能,会什么都不做,返回false;
但如果是以显示的方式window.XX or this.XX添加全局属性,则可直接后跟属性名进行删除:delete XX(严格模式会报错,需明确指定为对象的属性:delete this.XX)。
检测属性
- 属性或方法名(字符串) in 对象名:检测自有或继承属性,可区分不存在的属性和存在但值为Undefined的属性;
- o.hasOwnProperty():检测自有属性;
- o.propertyIsEnumerable():自有且可枚举;
- property !== undefined
存取器属性
这是ES 5中的规定,存取器属性是和属性同名的方法,不过不用function来声明,而是用get和set;当只声明了get时该属性只读不可写,当只声明set时该属性只写,读取该属性永远返回Undefined。访问存取器属性仍然使用 o.propertyName的方式。
参考:ECMAScript5中的对象存取器属性:getter和setter
属性的特性
属性的特性包括:
- value/get
- writable/set
- enumerable
- configurable
为什么要配置属性的特性重要:
- 可给原型对象添加新方法,且将其设置为不可枚举,看起来更像内置方法;
- 可给对象定义不能修改或删除的属性,借此“锁定”该对象。
获取对象的某个属性的特性:
Object.getOwnPropertyDescriptor(对象,“属性名”);该方法只能获取了属性的描述符对象,能够返回自有属性的特性,要获取继承属性的特性,需要遍历原型链。
设置属性的特性:
Object.defineProperty(对象,属性名,新的描述符对象)或Object.defineProperties同时设置多个属性的特性。
违反规则时调用上述方法会抛出类型错误,见书P136.
对象的三个属性
原型属性
ES 5提供了Object.getPrototypeOf()来查询对象的原型;
o.constructor.prototype也可检测(o.construtor指向对象的构造函数);
p.isPrototypeOf(o)用于检测p是否是o的原型对象。类属性
toString()方法会返回一个字符串(继承自Object.prototype),表示对象的类型信息:
[object class]
由于很多对象继承的toString()方法被重写了,例如Array类型的数据其toString方法被重写为将数组内部的元素返回成字符串,因此需要使用下面的方式获取对象的类型:
Object.prototype.toString.call(o)
由于只需要返回的字符串的第8位到倒数第2位的字符串,因此需要对返回的字符串进行后续处理,下面的函数可以处理null和Undefined类型的数据(这两者没有toString方法):
function classOf(o) {
if (o === null) return "Null";
if (o === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8,-1);
}
- typeOf能够区分的对象类型是:object、function,更具体的诸如Array、Date等都返回object。
- instanceOf用于判断是哪个类的实例。
3.可扩展性
表示是否可以给对象添加新的属性。
序列化对象
- JSON.stringify();
- JSON.parse()
对象、数组、字符串、无穷大数字、true、false、null都可序列化和还原,NaN、Infinity、-Infinity序列化结果是null;
函数、RegExp、Error、undefined不能序列化和还原;
JSON.stringify()只能序列化可枚举的自有属性。
Object.prototype中的一些方法
toString()
在需要将对象转换为字符串的时候调用该方法,例如用 + 连接字符串和一个对象或在期望使用字符串的地方使用了对象。
普通对象调用该方法返回 “[object object]”;
Array、Date、Function类型的变量调用该方法会有不同的返回值。toLocaleString()
普通对象调用该方法和调用toString没有区别,但数字、日期等类型的可以做出本地化的转换。
valueOf()
和toString很类似,但往往当JS需将对象转换为某种原始值而非字符串的时候才调用,如果在需要使用原始值的地方使用了对象JS会自动调用该方法。
其他
在期待使用对象的地方,请注意null也是一个对象。
当不能确定一个变量是否存在,如果直接使用if语句会报ReferenceError
(访问未声明的变量),最好使用typeof,此时返回值为undefined。但当是对象的属性/方法时则直接可以用if来判断,访问不存在的属性,实际上返回了Undefined。