重读Object

65 阅读5分钟

Object.assign()

Object.assign()静态方法将一个或者多个元对象中所有可枚举自由属性复制到目标对象,并返回修改后的目标对象

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget === target);
// Expected output: true

此处注意:

  1. 返回值是修改后的目标对象,也就是returnedTarget 等于target;
  2. 字符串Symbol类型属性都会被复制
  3. 如果复制期间出错,例如如果属性不可写,则会抛出TypeError;如果在抛出异常之前已经添加了一些属性,则这些属性会被保留,而target对象也会被修改
  4. Object.assign()不会在源对象为null或undefined时抛出错误
  5. Object.assign()不能实现深拷贝;针对深拷贝需要使用其他办法,因为 Object.assign() 只复制属性值
  6. 原型链上的属性和不可枚举的属性不能被复制
  7. 基本类型会被封装为对象
const v1 = "abc";
const v2 = true;
const v3 = 10;
const v4 = Symbol("foo");

const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 基本类型将被封装,null 和 undefined 将被忽略。
// 注意,只有字符串封装对象才拥有可枚举的自有属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

Object.create()

Object.create()静态方法以一个现有对象作为原型,创建一个新对象;

  • 语法:
Object.create(proto)
Object.create(proto, propertiesObject)

  • 参数
    • proto:新创建对象的原型对象
    • propertiesObject[可选]:如果该参数被指定且不为undefined,则该传入对象可枚举的自身属性将为新创建的对象添加具有对应名称的属性描述符。这些属性对应于Object.defineProperties()的第二个参数。
  • 返回值:根据指定的原型对象和属性创建的新对象; 注意:
  1. Object.create(null)返回的对象没有原型,可节约内存空间,当不需要原型的对象,可以该方法创建对象

Object.defineProperty()

判断对象的属性是否为可枚举的方法

let a={'o':1}
a.propertyIsEnumerable('o')//true

示例:演示一个可配置但不可写的数据属性。该属性的value仍然可以使用defineProperty进行替换(但不能使用复制运算符),并且writable特性仍然可以切换。

Object.defineProperty(o, "b", {
  writable: false,
  configurable: true,
});
Object.defineProperty(o, "b", {
  value: 1,
}); // 我们可以使用 defineProperty 方法替换属性的值
console.log(o.b); // 1
o.b = 2; // 在严格模式下抛出 TypeError:cannot change a non-writable property's value with assignment

示例:演示一个不可配置但可写的数据属性。该属性value仍然可以被更改,writable也仍然可以从true切换到false。

const o = {};
Object.defineProperty(o, "b", {
  writable: true,
  configurable: false,
});
console.log(o.b); // undefined
Object.defineProperty(o, "b", {
  value: 1,
}); // 即使 configurable 为 false,因为对象是可写的,我们仍然可以替换属性的值。
console.log(o.b); // 1
o.b = 2; // 我们也可以使用赋值运算符来更改属性的值
console.log(o.b); // 2
// 切换属性的可写性
Object.defineProperty(o, "b", {
  writable: false,
});
Object.defineProperty(o, "b", {
  value: 1,
}); // TypeError: because the property is neither writable nor configurable, it cannot be modified
// 此时,无法再次修改属性 'b' 或者恢复它的可写性。

Object.entries()

Object.entries()静态方法返回一个数组,包含给定队形自由的可枚举字符串键属性的键值对。该方法返回一个数组,其元素是直接在object上找到相应的可枚举字符串键属性的键值对数组。这与使用for...in循环迭代相同,只是使用for...in循环也枚举原型链中的属性。Object.entries()返回的数组顺序和for...in循环提供的顺序相同。

  • 在基本类型中使用Object.entries() 非对象参数会强制转换成对象。undefined和null不能被强制转换成对象,会抛出TypeError。只有字符串可以有自己的可枚举属性,所有其他基本类型均返回一个空数组。
// 字符串具有索引作为可枚举的自有属性
console.log(Object.entries("foo")); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]

// 其他基本类型(除了 undefined 和 null)没有自有属性
console.log(Object.entries(100)); // []

  • 将Object转换成Map Map()构造函数接受一个entries可迭代对象。使用Object.entries,可以很容易地将Object转换成Map:
const obj = { foo: "bar", baz: 42 };
const map = new Map(Object.entries(obj));
console.log(map); // Map(2) {"foo" => "bar", "baz" => 42}

Object.fromEntries()

Object.fromEntries()静态方法将键值对列表转换为一个对象

const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42],
]);

const obj = Object.fromEntries(entries);

console.log(obj);
// Expected output: Object { foo: "bar", baz: 42 }
  • 注意
  1. 与Array.from()不同的是,Object.fromEntries()不使用this的值,因此在另一个构造函数上调用它不会创建该类型的队形。
  2. 通过 Object.fromEntries、其逆操作 Object.entries() 和数组操作方法,你可以像这样转换对象:
const object1 = { a: 1, b: 2, c: 3 };

const object2 = Object.fromEntries(
  Object.entries(object1).map(([key, val]) => [key, val * 2]),
);

console.log(object2);
// { a: 2, b: 4, c: 6 }

Object.getOwnPropertyNames()

Object.getOwnPropertyNames()静态方法返回一个数组,其包含给定对象中所有属性(包括不可枚举属性,但不包括使用symbol值作为名称的属性)

Object.hasOwn()

如果指定的对象自身有指定的属性,则静态方法Object.hasOwn()返回true;如果属性是继承的或者不存在的,该方法返回false。

  • 语法:
Object.hasOwn(obj, prop)
obj:要测试的JS实例对象
prop:要测试属性的String类型的名称或者Symbol

注意:Object.hasOwn()旨在取代Object.prototype.hasOwnProperty()

Object.is()

Object.is()静态方法确定两个值是否为相同值,如果以下其中一项成立,则两个值相同:

  • 都是undefined
  • 都是null
  • 都是true或者都是false
  • 都是长度相同、字符相同、顺序相同的字符串
  • 都是相同的对象(意味着两个值都引用了内存中的同一个对象)
  • 都是BigInt且具有相同的字符串
  • 都是symbol且引用相同的symbol值
  • 都是数字且
    • 都是+0
    • 都是-0
    • 都是NaN
    • 都有相同的值,非零且都不是NaN Object.is()与==运算符并不等价。==运算符在测试相等性之前,会对两个操作数进行类型转换(如果他们不是相同的类型),这可能会导致一些非预期的行为,例如""==false的结果是true,但是Object.is()不会对其操作数进行转换。

Object.is()也不等价于===运算符。Object.is()与===之间唯一的区别是他们处理带符号的0和NaN值的时候。===运算符(和==运算符)将数值-0和+0视为相等,但是会将NaN视为彼此不相等