属性的简洁表示法
const obj = {
foo,
class() {}, // class是字符串,所以不会因为它属于关键字而报错
*m() {}, // Generator函数前面需要加上*
}
属性名表达式
// ES5
obj.foo = true; // 标识符作为属性名
obj['a' + 'bc'] = 123 // 表达式作为属性名
// ES6
let obj = {
['a' + 'bc']: 123
}
注意:如果表达式是一个对象默认情况下会被自动转为字符串[Object Object]
Object.is()
比较两个值是否严格相等与 === 行为一致但是可以判断+0 与-0 和 NaN
Object.is({}, {}) // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.assign()
将源对象所有的可枚举属性复制到目标对象,第一个参数为目标对象,后面的都是源对象。
- 后面的同名属性会覆盖前边的
- 如果只有一个参数会直接返回该参数
var obj = {a: 1};
Object.assign(obj) === obj // true,存储地址相同
- 参数不是对象会先转换为对象,null 和 undefined 无法转为对象,在首位会报错,在其他位置会跳过。其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了 字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
typeof Object.assign(2) // "Object"
var v1 = 'abc';
var v2 = true;
var v3 = 10;
var obj = Object.assign({}, v1, v2, v3);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
- 只会拷贝可枚举的实义属性和原对象的自身属性(不拷贝继承属性)
- 实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
- 可以处理数组,但会把数组视为对象
Object.assign([1, 2, 3], [4, 5]) // [4,5,3]
用途
- 为对象添加属性
class Point {
constructor(x, y) {
Object.assign(this, {x, y});
}
}
- 为对象添加方法
- 拷贝对象,但只能克隆原始对象自身的值,不能克隆它继承的值,要保持继承链可以采用下面代码
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
- 合并对象
- 为属性指定默认值
Object.assign({}, DEFAULTS, options);
属性的可枚举性和遍历
可枚举性
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行 为。 Object.getOwnPropertyDescriptor 方法可以获取该属性的描述对象。
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
描述对象的 enumerable 属性,称为”可枚举性“,如果该属性为 false 以下操作会忽略当前属性:
- for...in 循环:只遍历对象自身的和继承的可枚举的属性。
- Object.keys() :返回对象自身的所有可枚举的属性的键名。
- JSON.stringify() :只串行化对象自身的可枚举的属性。
- Object.assign() : 忽略 enumerable 为 false 的属性,只拷贝对象自身的可枚举的属性。
属性的遍历
- for...in: 循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
- Object.keys: 返回一个数组,包含对象自身的可枚举属性(不含 Symbol 属性)
- Object.getOwnPropertyNames(obj): 返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)。
- Object.getOwnPropertySymbols: 返回一个数组,包含对象自身的所有 Symbol 属性。
- Reflect.ownKeys: 返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举。
以上 5 种方法遍历对象属性都遵循以下次序规则:
- 首先遍历所有属性名为数值的属性,按照数字排序。
- 其次遍历所有属性名为字符串的属性,按照生成时间排序。
- 最后遍历所有属性名为 Symbol 值的属性,按照生成时间排序。
Object.getOwnPropertyDescriptors()
返回某个对象所有的自生属性的描述对象
使用场景
- 解决 Object.assign()无法正确拷贝 get 和 set 属性的问题
const shallowMerge = (target, source) => Object.defineProperties(target,Object.getOwnPropertyDescriptors(source));
- 配合 Object.create 方法,将对象属性克隆到一个新对象。这属于浅拷贝。
const clone = Object.create(Object.getPrototypeOf(obj),Object.getOwnPropertyDescriptors(obj));
- 实现一个对象继承另一个对象
const obj = Object.create(
prot,
Object.getOwnPropertyDescriptors({
foo: 123,
})
);
Object.setPrototypeOf()
ES6 推荐的设置原型对象的方法,用来设置一个对象的 prototype,如果第一个参数不是对象会转为对象,但返回的还是第一个参数,所以不会产生任何效果
let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
obj.x // 10
obj.y // 20
obj.z // 40
Object.getPrototypeOf()
该方法与 Object.setPrototypeOf 方法配套,用于读取一个对象的原型对象。参数不是对象会被转为对象
Object.keys()
返回一个对象自身(不含继承)所有可枚举属性的键名数组
Object.values()
返回一个对象自身(不含继承)所有可枚举属性的键值数组,会过滤属性名为 Symbol 值的属性。
Object.entries()
返回一个对象自身(不含继承)所有可枚举属性的键值对数组, 会过滤属性名为 Symbol 值的属性。
var obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
Object.fromEntries()
Object.entries()的反转
Object.fromEntries(new Map([ ['foo', 'bar'], ['baz', 42] ]))
// { foo: 'bar', baz: 42 }
Object.fromEntries([['foo', 'bar'], ['baz', 42]])
// { foo: 'bar', baz: 42 }
对象扩展运算符(...)
- 解构赋值,将所有的可遍历但尚未被读取的属性分配到制定的对象
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
- 扩展运算符,取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let newObj = { ...obj }
- 合并两个对象
{ ...obj1, ...obj2 }
Object.assign 与展开运算符的区别
相同点
- 行为一致
- 执行的都是浅拷贝
- 都是将已有对象的所有可枚举属性拷贝到新构造的对象中
不同点
- Object.assign() 函数会触发 setters,而展开语法则不会
Null 传导运算符(提案)
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
// 简化如下:
const firstName = message?.body?.user?.firstName || 'default';
四种用法:
- obj?.prop // 读取对象属性
- obj?.[expr] // 同上
- func?.(...args) // 函数或对象方法的调用
- new C?.(...args) // 构造函数的调用