【重学前端】ECMAScript6 - 对象的扩展和新增方法

176 阅读4分钟

对象的扩展和新增方法

对象的简写

  • 对象属性简写
let a = 'hello';
let b = { a }; // 相当于{ a: a }

function func(){
  let c = 'world'
  return { c }; // 相当于 { c: c }
}
console.log(b, func()); // {a: 'hello'} {c: 'world'}
  • 对象方法简写
let obj = {
  func() {}
}
// 等同于
let obj = {
  func: function() {}
}

注意:简写方法不能用作构造函数。

let obj = {
  i: 0,
  Func() {
    console.log(this)
  }
}
console.log(obj.Func()); // {i: 0, Func: ƒ}
let func = new obj.Func(); // Uncaught TypeError: obj.Func is not a constructor

属性名

如果对象的属性名是一个变量,需要注意这个变量的类型。

// 变量是数值时
let key = 1;
let obj = {
  [key]: 'hello'
}
console.log(obj, typeof Object.keys(obj)[0]); // {1: 'hello'} 'string'

// 变量是Symbol时
let key = Symbol(1);
let obj = {
  [key]: 'hello'
}
console.log(obj, typeof Object.keys(obj)[0], obj[key]); // {Symbol(1): 'hello'} 'undefined' 'hello'
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(1)]

// 变量是对象时
let key = {};
let obj = {
  [key]: 'hello'
}
console.log(obj); // {[object Object]: 'hello'}

// 变量是数组时
let key = [];
let obj = {
  [key]: 'hello'
}
console.log(obj); // {"": 'hello'}

// 变量是布尔值时
let key = true;
let obj = {
  [key]: 'hello'
}
console.log(obj, typeof Object.keys(obj)[0]); // {true: 'hello'} 'string'

// 变量是BigInt时
let key = 123n;
let obj = {
  [key]: 'hello'
}
console.log(obj, typeof Object.keys(obj)[0]); // {123: 'hello'} 'string'

对象属性的遍历

  • for ... in 可以遍历对象所有可枚举的属性,包括对象本身和对象继承来的属性。
  • Obhect.keys(obj) 返回对象自身所有可枚举的属性名
  • Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身所有属性,包括不可枚举的属性,但不包含Symbol属性
  • Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身所有Symbolg属性,包括不可枚举的Symbol属性
  • Reflect.ownKeys(obj)返回一个数组,包含对象自身所有属性(包含不可枚举的),不管是不是Symbol属性,但不包含继承的。

示例如下:

function Father(name, age) {
  this.name = name;
  this.age = age;
}
Father.prototype = {
  gender: 'male'
}


function Son(name, age) {
  Father.call(this, name, age)
}
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;

let father = new Father('老明', '38');
Object.defineProperty(father, 'job', {// 此时father对象有两个枚举属性namge,age,一个不可枚举属性job,一个原型上的属性gender
  value: 'CEO',
  enumerable: false
})

let son = new Son('小明', 12); // son自身有name,age,Symbol(1)三个可枚举属性
son[Symbol(1)] = 'symbol 1';

Object.defineProperty(son, 'job', {
  value: '小学生',
  enumerable: false
});

Object.defineProperty(son, Symbol(2), {// son有两个不可枚举属性job,Symbol(2)
  value: 'symbol 2',
  enumerable: false
})

// for in 会输出继承来的可枚举属性
for(key in son) {
  console.log(key); // 分别输出name age constructor gender
}

// Object.keys()输出自身可枚举属性
console.log(Object.keys(son)); // ['name', 'age']

// Object.getOwnPropertyNames输出自身可枚举和不可枚举的非Symbol类型属性
console.log(Object.getOwnPropertyNames(son)); // ['name', 'age', 'job']

// Object.getOwnPropertySymbols()输出自身可枚举和不可枚举的Symbol类型属性
console.log(Object.getOwnPropertySymbols(son)); // [Symbol(1), Symbol(2)]

// Reflect.ownKeys()输出自身所有属性
console.log(Reflect.ownKeys(son)); // ['name', 'age', 'job', Symbol(1), Symbol(2)]

Object.is()

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

有两个不同点:+0不等于-0;NaN等于自身。

+0 === -0 //true
NaN === NaN // false

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

Object.assign()

Object.assign()用于合并对象,接收N个参数,第一个参数为目标对象,剩余参数为源对象,源对象合并到目标对象,注意,合并的是源对象自身可枚举的属性,同时需注意浅拷贝问题。

let obj = {
  a: 1,
}

let obj2 = {
  b: 2
}
Object.defineProperty(obj2, 'c', {
  enumerable: false,
  value: 3
})

console.log(Reflect.ownKeys({...obj, ...obj2})); // ['a', 'b']
console.log(Reflect.ownKeys(Object.assign(obj, obj2))); // ['a', 'b']
console.log(obj); // {a: 1, b: 2}
// 可以看出Object.assign和解构赋值的方式合并没多大差别。
// 需要注意,如果合并的源变量不是对象时,如果是字符串,会对字符串做解构赋值,如果是数值或布尔值,不生效。
let obj = {
  a: 1,
}

let obj2 = 'abc';
let obj3 = 100;
let obj4 = true;
console.log({...obj, ...obj2, ...obj3, ...obj4}); // {0: 'a', 1: 'b', 2: 'c', a: 1}

Object.assign(obj, obj2, obj3, obj4);

console.log(obj); // {0: 'a', 1: 'b', 2: 'c', a: 1}

Object.setProtytypeOf(), Object.getPrototypeOf()

用来处理__proto__属性。之前我们做原型链处理可能会使用这个属性来绑定原型。但现在我们用这两个Object方法来处理。

const obj = {
  hello: 'world'
}

function Person(){}
Person.prototype = {
  abc:'abc'
}
obj.__proto__ = Person.prototype;
console.log(obj.abc); // 'abc'

现在我们改成:

const obj = {
  hello: 'world'
}

function Person(){}
Person.prototype = {
  abc:'abc'
}
Object.setPrototypeOf(obj, Person.prototype);
console.log(obj.abc); // 'abc'
console.log(Object.getPrototypeOf(obj)); // {abc: 'abc'}

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

都是返回数组。和数组的keys()values()entries()方法区分一下,数组的是返回一个迭代器对象。

Object.fromEntries()

Object.entries()的逆操作。将一个键值对数组转成对象。

// 比如我们可以将一个map对象转成普通对象
const map = new Map();
map.set('a', 1);
map.set('b', 2);

console.log(Object.fromEntries(map)); // {a: 1, b: 2}

参考