理解对象
- 创建自定义对象的通常方式是创建object的一个新实例,然后再给它添加属性和方法。
- 也可以使用对象字面量进行创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let person = new Object(); person.name = "Nicholas"; person.age = 29; person.job = "Software Engineer"; person.sayName = function() { console.log(this.name); };
let person = { name: "Nicholas", age: 29, job: "Software Engineer", sayName() { console.log(this.name); } };
|
属性类型
数据属性
- 数据属性包含一个保存数据值的位置。
- 值会从这个位置读取,也会写入到这个位置。
- 数据属性有4个特性描述它们的行为。
- 要修改属性的默认特性,就必须使用Object.defineProperty ()方法。
- 这个方法接收3个参数:要给其添加属性的对象、属性的名称和一个描述符对象。最后一个参数,即描述符对象上的属性可以包含: configurable、enumerable、writable和 value,跟相关特性的名称一一对应。根据要修改的特性,可以设置其中一个或多个值。
- 在调用Object.defineProperty()时, configurable,enumerable和writable的值如果不指定,则都默认为 false
- 在严格模式下,尝试修改只读属性的值会抛出错误。
1 2 3 4 5 6 7 8
| let person = {}; Object.defineProperty(person, "name", { writable: false, value: "Nicholas" }); console.log(person.name); person.name = "Greg"; console.log(person.name);
|
- 一个属性被定义为不可配置之后,就不能再变回可配置的了。再次调用object.defineProperty()并修改任何非 writable属性会导致错误。
1 2 3 4 5 6 7 8 9 10
| let person = {}; Object.defineProperty(person, "name", { configurable: false, value: "Nicholas" });
Object.defineProperty(person, "name", { configurable: true, value: "Nicholas" });
|
访问器属性
- 访问器属性不包含数据值。
- 访问器属性有4个特性描述它们的行为。
- 访问器属性是不能直接定义的,必须使用Object.defineProperty ()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| let book = { year_: 2017, edition: 1 }; Object.defineProperty(book, "year", { get() { return this.year_; }, set(newValue) { if (newValue > 2017) { this.year_ = newValue; this.edition += newValue - 2017; } } }); book.year = 2018; console.log(book.edition);
|
在这个例子中,对象book 有两个默认属性: year_和 editiono。year_中的下划线常用来表示该属性并不希望在对象方法的外部被访问。另一个属性year被定义为一个访问器属性,其中获取函数简单地返回year_的值,而设置函数会做一些计算以决定正确的版本( edition )。因此,把year属性修改为2018会导致year_变成2018,edition变成2。这是访问器属性的典型使用场景,即设置一个属性值会导致一些其他变化发生。
定义多个属性
- Object.defineProperties()方法可以通过多个描述符一次性定义多个属性。
- 它接收两个参数:要为之添加或修改属性的对象和另一个描述符对象,其属性与要添加或修改的属性一一对应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| let book = {};
Object.defineProperties(book, { year_: { value: 2017 }, edition: { value: 1 }, year: { get() { return this.year_; }, set(newValue) { if (newValue > 2017) { this.year_ = newValue; this.edition += newValue - 2017; } } } });
|
读取属性的特征
- Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。
- 方法接收两个参数:属性所在的对象和要取得其描述符的属性名。
- 返回值是一个对象,对于访问器属性包含configurable、enumerable、get和 set)属性,对于数据属性包含configurable、enumerable,writable和 value属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| let book = {}; Object.defineProperties(book, { year_: { value: 2017 }, edition: { value: 1 }, year: { get: function() { return this.year_; }, set: function(newValue){ if (newValue > 2017) { this.year_ = newValue; this.edition += newValue - 2017; } } } }); let descriptor = Object.getOwnPropertyDescriptor(book, "year_"); console.log(descriptor.value); console.log(descriptor.configurable); console.log(typeof descriptor.get); let descriptor = Object.getOwnPropertyDescriptor(book, "year"); console.log(descriptor.value); console.log(descriptor.enumerable); console.log(typeof descriptor.get);
|
- Object.getOwnPropertyDescriptors ()静态方法实际上会在每个自有属性上调用Object.getOwnPropertyDescriptor()并在一个新对象中返回它们。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| let book = {}; Object.defineProperties(book, { year_: { value: 2017 }, edition: { value: 1 }, year: { get: function() { return this.year_; }, set: function(newValue){ if (newValue > 2017) { this.year_ = newValue; this.edition += newValue - 2017; } } } }); console.log(Object.getOwnPropertyDescriptors(book));
|
合并对象
- ECMAScript 6专门为合并对象提供了**Object.assign()**方法,这个方法接收一个目标对象和一个或多个源对象作为参数,然后将每个源对象中可枚举(Object.propertyIsEnumerable()返回true)和自有(Object.hasOwnProperty()返回true)属性复制到目标对象。
- 以字符串和符号为键的属性会被复制。
- 对每个符合条件的属性,这个方法会使用源对象上的[[Get]]取得属性的值,然后使用目标对象上的[ [Set]]设置属性的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| let dest, src, result;
dest = {}; src = { id: 'src' }; result = Object.assign(dest, src);
console.log(dest === result); console.log(dest !== src); console.log(result); console.log(dest);
dest = {}; result = Object.assign(dest, { a: 'foo' }, { b: 'bar' }); console.log(result);
dest = { set a(val) { console.log(`Invoked dest setter with param ${val}`); } }; src = { get a() { console.log('Invoked src getter'); return 'foo'; } }; Object.assign(dest, src);
console.log(dest);
|
- Object.assign()实际上对每个源对象执行的是浅复制。
- 如果多个源对象都有相同的属性,则使用最后一个复制的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| let dest, src, result;
dest = { id: 'dest' }; result = Object.assign(dest, { id: 'src1', a: 'foo' }, { id: 'src2', b: 'bar' });
console.log(result);
dest = { set id(x) { console.log(x); } }; Object.assign(dest, { id: 'first' }, { id: 'second' }, { id: 'third' });
dest = {}; src = { a: {} }; Object.assign(dest, src);
console.log(dest); console.log(dest.a === src.a);
|
- 如果赋值期间出错,则操作会中止并退出,同时抛出错误。