了解JavaScript中最重要的数据结构-对象(object)的方法和简洁操作

281 阅读4分钟

1.Object.defineProperty() :定义属性的特性

这个方法有3个参数:要添加属性的对象、属性的名称、描述符对象;
描述符对象上的属性包含:
数据属性:configurable(表示属性是否可以通过delete删除或重新定义,是否可以修改它的特性,是否可以改为访问器属性)、enumerable(表示属性是否可以通过for···in循环返回)、writable(表示属性值是否可以被修改)、value(属性实际的值);
访问器属性:configurable、 enumerable、get、set
默认情况下,将属性直接显示添加到对象上,configurable,enumerable,writable都被设置为true,value被设置为指定的值

let person = {}
Object.defineProperty(person, "name", {
  writable: false,
  value: "CR7"
})
console.log(person.name);  //"CR7"
person.name = "Messi"
console.log(person.name);  //"CR7"  只读无法修改
let person = {}
Object.defineProperty(person, "name", {
  configurable: false,
  value: "CR7"
})
console.log(person.name); //"CR7"
delete person.name
console.log(person.name);  //"CR7"  不能删除
let person = {}
Object.defineProperty(person, "name", {
  configurable: false,
  value: "CR7"
})

Object.defineProperty(person, "name", {
  configurable: true,
  value: "CR7"
})  //TypeError: Cannot redefine property: name
let person = {
  _name: "CR7"
}
Object.defineProperty(person, "name", {
  configurable: true,
  enumerable: true,
  get() {
    console.log("调用get属性");
    return this._name
  },
  set(value) {
    console.log("调用set属性");
    this._name = value
  }
})

console.log(person.name);
//调用get属性
//CR7
person.name = "Messi"
//调用set属性
console.log(person.name);
//调用get属性
// Messi

在调用Object.defineProperty()时,configurable、enumerable、writable默认为false
定义多个对象,使用Object.defineProperties()

2.Object.getOwnPropertyDescriptor():读取属性的特性

该方法返回指定对象上一个自有属性对应的属性描述符对象,(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

let o = {
  get foo() {
    return 17
  }
}
const d = Object.getOwnPropertyDescriptor(o, "foo")
console.log(d)
// {
//   get: [Function: get foo],
//   set: undefined,
//   enumerable: true,
//   configurable: true
// }

ES2017新增Object.getOwnPropertyDescriptors()方法用来获取一个对象的所有自身属性的描述符对象,这个方法实际上会在每个自有属性上调取Object.getOwnPropertyDescriptor()

let o = {
  get foo() {
    return 17;
  }
};
Object.defineProperty(o, "name", {
  value: "CR7",
})
const d = Object.getOwnPropertyDescriptors(o)
console.log(d);
// {
//   foo: {
//     get: [Function: get foo],
//     set: undefined,
//     enumerable: true,
//     configurable: true
//   },
//   name: {
//     value: 'CR7',
//     writable: false,
//     enumerable: false,
//     configurable: false
//   }
// }

3.Object.assign():对象合并

接收一个目标对象和一个或多个源对象为参数,然后将每个源对象中的可枚举(Object.propertyIsEnumerable()返回true)和自有(Object.hasOwnProperty()返回true)属性复制到目标对象
Object.assign()修改目标对象,也会返回修改后的目标对象

为对象添加属性

const target = {
  a: 1
};
const source1 = {
  b: 2
};
const source2 = {
  c: 3
};
const result = Object.assign(target, source1, source2)
console.log(target) //{ a: 1, b: 2, c: 3 }
console.log(result === target) //true

克隆对象

const target = {
  a: 1
};
const source1 = {
  b: 2
};
const result = Object.assign({}, target, source1)
console.log(result) //{a: 1, b: 2}

同名属性的替换

如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性

const target = {
  a: 1,
  b: 1
};
const source1 = {
  b: 2,
  c: 2
};
const source2 = {
  c: 3
};
Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}

如果只有一个参数,Object.assign()会直接返回该参数

const obj = {
  a: 1
};
console.log(Object.assign(obj) === obj); // true

浅拷贝,只复制对象的引用

const obj1 = {
  a: {
    b: 1
  }
};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
console.log(obj2.a.b); // 2

不能在两个对象间转移get和set函数

Object.assign()只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制

const source = {
  get foo() {
    return 1
  }
};
const target = {};
Object.assign(target, source)
console.log(target); // { foo: 1 }

4.Object.is():对象标识及相等判定

===的缺点:NaN不等于自身,以及+0等于-0

console.log(+0 === -0) //true
console.log(NaN === NaN) //false

Object.is()与严格比较运算符(===)的行为基本一致,

Object.is('foo', 'foo') // true
Object.is({}, {}) // false

不同之处只有两个:一是+0不等于-0,二是NaN等于自身

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

5.对象的扩展运算符

解构赋值

对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

等号右边是undefinednull,解构赋值不是最后一个参数,都会报错

let { ...x, y, z}={ x: 1, y: 2, a: 3, b: 4 } //SyntaxError: Rest element must be last element

解构赋值的拷贝是浅拷贝

let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2

扩展运算

Object.assign()方法克隆对象相同

const source1 = {
  b: 2
};
const source2 = {
  c: 3
};
const result1 = Object.assign({}, source1, source2)
const result2 = {
  ...source1,
  ...source2
}
console.log(result1);//{ b: 2, c: 3 }
console.log(result2);//{ b: 2, c: 3 }

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

const obj = {
  x: 1,
  y: 2,
  a: 3,
  b: 4
}
console.log(Object.keys(obj));
// [ 'x', 'y', 'a', 'b' ]
console.log(Object.values(obj));
// [ 1, 2, 3, 4 ]
console.log(Object.entries(obj));
// [ [ 'x', 1 ], [ 'y', 2 ], [ 'a', 3 ], [ 'b', 4 ] ]

配合for...of循环使用