对象
什么是对象?
- ECMA-262把对象定义为:无需属性的集合,其属性可以包含基本值、对象或者函数
- 简单理解,对象无非就是一组键值对(key-value):对象的每一个属性和方法都有一个名字,每个名字都映射到一个值,而这个值要么是数据,要么是函数。
- 对象都是基于引用类型创建的,这句话有2层含义:
- 第一,引用类型可以是原生类型,也可以是自定义类型
- 第二,对象是某个引用类型的实例
如何创建对象(上)
如何创建对象设计的内容较多,分为2部分
其实创建对象很简单,比如我们创建一个Object对象,也就是Object类型的实例,有2种方法:
第一种:使用new+构造函数
var person = new Object();
这就创建了一个Object对象,这个对象的名字叫person
有点女娲造人的感觉,Object()构造函数就像女娲手里的鞭子,沾上泥水甩一把就创造出来一个人
然后我们给这个person添加一点属性
var person = new Object();
person.name = "ta";
person.age = 92;
那么这个人有了名字,叫ta;有了年龄,92
第二种:对象字面量表示法
var person = {
name : "ta",
age : 92
};
这样也创建了一个对象,对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程。
对象字面量也是向函数传递大量可选参数的首选方式。
function displayInfo(args) {
var output = "";
if (typeof args.name == "string"){
output += "Name: " + args.name + "\n";
}
if (typeof args.age == "number") {
output += "Age: " + args.age + "\n";
}
alert(output);
}
displayInfo({
name: "Nicholas",
age: 29
});
displayInfo({
name: "Greg"
});
如何访问对象的属性
第一种:点表示法
var theName = person.name;
第二种:方括号表示法
var theName = person["name"];
方括号表示法的优点是可以使用变量访问属性
//比如定义了变量propertyName
var propertyName = "name";
var theName = person[propertyName];
通常,除非必须使用变量来访问属性,否则我们建议使用点表示法。
理解对象的属性
属性类型
- 每个对象都有属性和方法,而对象的属性分为两种:
- 数据属性
- 访问器属性
- 说明:
- 数据属性包含数据值,而访问器属性不包含数据值
- 数据属性可以理解成对象存储其数据的地方,而访问器属性对应的是get和set操作
1. 数据属性
属性的英文名叫property,每个property都有4个特性(英文名叫attribute)描述其状态
(1) 数据属性的4个特性
- [[configurable]],默认值为true,表示是否可配置,包括:
- 能否通过delete删除属性从而重新定义属性
- 能否修改属性特性
- 能否把属性修改为访问器属性
- [[enumerable]],默认值为true,表示是否可枚举,即:
- 能否通过for-in循环
- [[writable]],默认值true,表示是否可写入,即:
- 能否修改属性的值
- [[value]],默认为undefined(注意不是null),包含属性的数据值。读取属性值的时候从这个位置读取,写入属性值的时候保存在这个位置
(2) 如何删除属性
使用delete
**语法:**delete obj.propertyName 或者 delete obj[propertyName]
**说明:**delete只能删除对象的自有属性,不能删除继承属性。
(3) 如何修改特性
Object.defineproperty()方法
Object.defineproperty(对象,"属性名",{
configurable:false,
eumerable:false,
writable:false,
value:"修改之后的值"
});
(4) 使用Object.defineProperty()需要注意的2点
- 一旦configurable设置为不可配置的,就无法再把它变为可配置的了
- 在调用 Object.defineProperty() 方法时,如果不指定, configurable 、 enumerable 和writable 特性的默认值都是 false 。
var Person = {
name: "Obama"
};
//调用 Object.defineProperty() 方法定义新属性,这个属性的特性中configurable,enumerable,writable默认为false,会导致了新属性不可写、不可枚举、不可再次配置
Object.defineProperty(Person, 'newKey', {});
//设置值
Person.newKey = 'Hello';
//枚举
console.log(Object.getOwnPropertyDescriptors(Person));
2. 访问器属性
(1) 访问器属性的4个特性
- [[configurable]],默认true
- [[enumerable]],默认true
- [[get]],默认undefined
- [[set]],默认undefined
(2) 如何添加访问器属性(2种方法)
访问器属性不能直接定义
- 通过Object.defineProperty()添加访问器
var book = {
_year: 2004,
edition: 1
};
Object.defineProperty(book, "year", {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
book.year = 2005;
alert(book.edition); //2
表示只能通过对象方法访问的属性前面约定俗成地加一个下划线,比如_year
- get不带任何参数,必须有return值
- set只能有一个参数,这个参数就是给这个访问器属性赋的值,任何return都是无效的
- 访问器属性的名称对应set函数的参数
不一定非要同时指定 get和 set。只指定 get 意味着属性只读,尝试写入属性会被忽略
- 通过__defineGetter__()和__defineSetter()__方法
var book = {
_year: 2004,
edition: 1
};
//定义访问器的旧有方法
book.__defineGetter__("year", function(){
return this._year;
});
book.__defineSetter__("year", function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
});
book.year = 2005;
alert(book.edition); //2
(3) 什么时候希望使用访问器?
如果希望一个属性值的变化会导致另一个属性值的变化,可以设置访问器属性
6.1.2 Object.defineProperties()方法
使用Object.defineProperties()方法可以同时定义多个属性,包括数据属性和访问器属性
var book = {};
Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
6.1.3 读取属性的特性的方法
(1) Object.getOwnPropertyDescriptor()
只能访问属性的一个特性
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value); //2004
alert(descriptor.configurable); //false
(2) Object.getOwnPropertyDescriptors()
可以访问属性的所有特性
var descriptors = Object.getOwnPropertyDescriptor(book);