有很多时刻,你惊心动魄,而世界一无所知;你翻山越岭,而大地寂静无声。
今日学习内容
1、JS 红皮书 P209-212 第八章:对象、类与面向对象编程
今日笔记
1、读取属性的特性: 使用 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);
|
ECMAScript 2017 新增了 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));
|
2、合并对象: JavaScript 开发者经常觉得“合并”(merge)两个对象很有用。更具体地说,就是把源对象所有的本地属性一起复制到目标对象上。有时候这种操作也被称为“混入”(mixin),因为目标对象通过混入源对象的属性得到了增强。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 28
| 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); `
|
如果赋值期间出错,则操作会中止并退出,同时抛出错误。Object.assign()没有“回滚”之前赋值的概念,因此它是一个尽力而为、可能只会完成部分复制的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| let dest, src, result;
dest = {}; src = { a: "foo", get b() { throw new Error(); }, c: "bar", }; try { Object.assign(dest, src); } catch (e) {}
console.log(dest);
|