ES 6 系列之对象的扩展

属性的简单表示

ES 6 允许将属性写在 {} 中,直接写入变量和函数,作为对象的属性和方法。这样的书写方式更加简洁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const foo = 'foo';
function getName() {
console.log('name');
}
const obj = { foo, getName };

console.log(obj); // { foo: 'foo', getName: ƒunction }

// ES 6
const obj = {
foo: 'foo',
getName: function () {
console.log('name');
},
};
console.log(obj); // { foo: 'foo', getName: function }

属性的可枚举性和遍历

可枚举性

对象的每个属性都有一个描述对象,用来控制该属性的行为。
Object.getOwnPropertyDescriptor 方法来获取该属性的描述对象。

1
2
3
4
5
6
7
8
const obj = { x: 1 };
console.log(Object.getOwnPropertyDescriptor(obj));
// {
// "value": 1,
// "writable": true,
// "enumerable": true,
// "configurable": true
// }

描述对象的 enumerable 属性,称为可枚举性,如果该属性为 false,就会被某些操作忽略。

操作会忽略 enumerablefalse 的属性。

  • for...in 循环:遍历对象自身和继承的可枚举属性。
  • Object.keys():返回对象所有可枚举的属性的 key
  • JSON.stringify():只串行化对象自身的可枚举的属性。
  • Object.assign():只拷贝对象自身的可枚举属性。

属性遍历

  • for…in
    for...in 循环对象自身的和继续的可枚举属性
1
2
3
4
5
6
7
const obj = { x: 1, y: 2, z: 3 };
for (let o in obj) {
console.log(o);
}
// x
// y
// z
  • Object.keys(obj)
    Object.keys(obj) 返回一个数组,包含所有可枚举属性的 key
1
2
3
4
5
6
7
const obj = { x: 1, y: 2, z: 3 };
for (let o of Object.keys(obj)) {
console.log(o);
}
// x
// y
// z
  • Object.getOwnPropertyNames(obj)
    Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性的 key
1
2
3
4
5
6
7
const obj = { x: 1, y: 2, z: 3 };
for (let o of Object.getOwnPropertyNames(obj)) {
console.log(o);
}
// x
// y
// z
  • Object.getOwnPropertySymbols(obj)
    Object.getOwnPropertySymbols(obj) 返回一个数组,包含对象自身的所有 Symbol 属性的 key
    打印的属性均为 Symbol
1
2
3
const obj = { [Symbol('x')]: 1, y: 2, z: 3 };
console.log(Object.getOwnPropertySymbols(obj));
// [Symbol(x)]
  • Reflect.ownKeys(obj)
    Reflect.ownKeys(obj) 返回一个数组,包含对象自身所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
1
2
3
const obj = { [Symbol('x')]: 1, y: 2, z: 3, 1: 10, 2: 11 };
console.log(Reflect.ownKeys(obj));
// ['1', '2', 'y', 'z', Symbol(x)]

一共五种遍历 key 的方式,但是遍历的次序是有规则的。

  • 首先遍历所有数值,并按照升序排列
  • 其次遍历字符串,按照加入时间升序
  • 最后才是 Symbol,按照加入时间升序

对象的扩展运算符

解构赋值数组的扩展 中,我们分别提到过对象的解构赋值以及扩展运算符。

我们来看看扩展运算符在对象中的使用。

解构赋值

我们来回顾一下 解构赋值

1
2
3
const { x, y } = { x: 1, y: 2 };
console.log(x); // 1
console.log(y); // 2
  • 使用扩展运算符时需要注意的是,解构赋值必须是最后一个参数且只能有一个,否则报错。
1
2
3
4
5
6
const { x, ...obj } = { x: 1, y: 2, z: 3 };
console.log(x); // 1
console.log(obj); // { y: 1, z: 2 }

const { ...obj, z } = { x: 1, y: 2, z: 3 };
console.log(obj); // 报错
  • 对象的解构赋值右侧不能是 undefinednull,会报错
1
2
3
const { ...obj } = null;
const { ...obj } = undefined;
// TypeError

扩展运算符

对象的扩展运算符用于取出参数对象的所有可便利属性,拷贝到当前对象之中。

1
2
3
const obj = { x: 1, y: 2 };
const obj2 = { ...obj };
console.log(obj); // { x: 1, y: 2 }
  • 数组也是特殊的对象,所以对象的扩展运算符也可以用于数组。
1
2
3
const obj = { ...['1', '2', '3'] };
console.log(obj);
// { 0: '1', 1: '2', 2: '3' }
  • 如果是空对象,则没有任何效果。
1
2
const obj = { ...{}, x: 1 };
console.log(obj); // { x: 1 }
  • 如果扩展运算符并不是对象,则会被自动转化成对象,但是部分值没有自身属性,所以会返回一个空对象 {}
1
2
3
4
const obj = { ...1 }; // 等同于 { ...Object(1) }
const obj2 = { ...true }; // { ...Object(true) }
const obj3 = { ...undefined }; // { ...Object(undefined) }
const obj4 = { ...null }; // { ...Object(null) }
  • 如果后面跟着字符串,则会自动转成类数组对象
1
2
const obj = { ...'hzq' };
console.log(obj); // { 0: 'h', 1: 'z', 2: 'q' }

对象新增的常用实例方法

Object.is()

Object.is() 是用来判断两个是否严格相等,与严格比较运算符 === 行为基本一致。

1
2
3
console.log(Object.is('hello', 'world')); // false
console.log(Object.is('hello', 'hello')); // true
console.log(Object.is({}, {})); // false

=== 不同点

1
2
3
4
5
console.log(+0 === -0); // true
console.log(NaN === NaN); // false

console.log(Object.is(+0, -0)); // false
console.log(Object.is(NaN, NaN)); // true

Object.assign()

Object.assign() 放啊主要用于对象的合并,将对象的所有可枚举属性复制到目标对象

1
2
3
4
5
6
const obj = {};
const obj1 = { x: 1 };
const obj2 = { y: 2 };
Object.assign(obj, obj1, obj2);
console.log(obj);
// { x: 1, y: 2 }

从上面我们可以看出,第一个参数就是目标对象,将后面对象的所有可枚举属性复制到第一个参数。

  • 如果后面参数中,有同名属性,则目标对象中的值,会被新的对象替代
  • 如果只有一个参数,则直接返回该参数
1
2
3
4
5
6
7
8
9
10
const obj = { x: 1 };
const obj1 = { x: 3, y: 2 };
const obj2 = { y: 4 };
Object.assign(obj, obj1, obj2);
console.log(obj);
// { x: 3, y: 4 }

const obj3 = { x: 3 };
console.log(Object.assign(obj3) === obj3);
// true
  • 如果参数不是对象,会被转成对象,然后返回
  • undefinednull 无法转成对象,会报错
1
2
3
4
5
6
console.log(Object.assign(1));
// Number {1}
console.log(typeof Object.assign(1));
// object
console.log(Object.assign(undefined)); // 报错
console.log(Object.assign(null)); // 报错

Object.keys(),Object.values(),Object.entries()

Object.keys()

Obejct.keys()ES 5 引入的,我们还是在这里稍微提一下。Object.keys()返回对象键值的数组,然后用来遍历对象的 key。

1
2
3
4
5
6
7
const obj = { x: 1, y: 2, z: 3 };
for (let key of Object.keys(obj)) {
console.log(key);
}
// x
// y
// z

Object.values()

Object.values()ES 6 时引入的,返回一个数组,是每个键对应的值。返回值的顺序可以参照,对象的可枚举性中顺序。

当然许多特性是类似的。

  • 返回的是可遍历的值,enumerabletrue
  • 如果转化的值不是对象,则会先转化为对象。
    • 字符串会被转为数组输出,
    • 布尔值、数值都不会为实例添加非继承的属性,返回空数组
    • Symbol 作为 key 会被忽略
1
2
3
4
5
6
7
8
9
10
11
12
13
const objVal = { 1: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(objVal));
// ["b", "c", "a"]
const obj = { [Symbol()]: 1, x: 2, y: 3 };
console.log(Object.values(obj));
// [2, 3];
const str = 'hello';
console.log(Object.values(str));
// ['h', 'e', 'l', 'l', 'o'];
console.log(Object.values(true));
// []
console.log(Object.values(11));
// []

Object.entries()

Object.entries() 方法返回一个数组,成员是参数对象自身的所有可遍历属性的键值对数组。

1
2
3
const obj = { x: 1, y: 2, z: 3 };
console.log(Object.entries(obj));
// [["x", 1], ["y", 2], ["z", 3]]
  • 对象的属性名是一个 Symbol 值,该属性会被忽略。
1
2
3
const obj = { [Symbol()]: 1, x: 2 };
console.log(Object.entries(obj));
// [['x', 2]]

两个用途

  • 遍历对象的属性
1
2
3
4
5
6
const obj = { x: 1, y: 2 };
for (let [k, v] of Object.entries(obj)) {
console.log(`key = ${k}, val = ${v}`);
}
// key = x, val = 1
// key = y, val = 2
1
2
3
4
const obj = { x: 1, y: 2 };
const map = new Map(Object.entries(obj));
console.log(map);
// Map { x: 1, y: 2 }

Object.fromEntries()

Object.fromEntries()Object.entries() 的逆向操作,用于将一个键值对数组转为对象

1
2
3
4
5
6
7
const arr = [
['x', 1],
['y', 2],
['z', 3],
];
console.log(Object.fromEntries(arr));
// { x: 1, y: 2, z: 3 }

用途

主要作用就是,是将键值对的数据结构还原为对象

1
2
3
4
5
6
let map = new Map();
map.set('x', 1);
map.set('y', 2);
map.set('z', 3);
console.log(Object.fromEntries(map));
// { x: 1, y: 2, z: 3 }

对象的扩展,我们就先介绍到这里,如果有问题,会对文章进行更新。

感谢各位的观看!

-------------------- 本文结束 感谢阅读 --------------------