Object.assign() - JavaScript

简介: Object.assign() - JavaScript

@[TOC]

一、分析

Object.assign(target, ...sources)

  • target:目标对象,接收源对象属性的对象,也是修改后的返回值。

  • sources:源对象,包含将被合并的属性。

  • 返回值:目标对象

    描述

    如果目标对象与源对象具有相同的 key,则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的属性。

Object.assign 方法只会拷贝源对象 可枚举的 和 自身的 属性到目标对象。该方法使用源对象的 [[Get]] 和目标对象的 [[Set]],它会调用 getters 和 setters。故它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含 getters,这可能使其不适合将新属性合并到原型中。

为了将属性定义(包括其可枚举性)复制到原型,应使用 Object.getOwnPropertyDescriptor() 和 Object.defineProperty(),基本类型 String 和 Symbol 的属性会被复制。

如果赋值期间出错,例如如果属性不可写,则会抛出 TypeError;如果在抛出异常之前添加了任何属性,则会修改 target 对象(译者注:换句话说,Object.assign() 没有“回滚”之前赋值的概念,它是一个尽力而为、可能只会完成部分复制的方法)。

备注: Object.assign() 不会在 source 对象值为 null 或 undefined 时抛出错误。

二、Demo

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);
// expected output: Object { a: 1, b: 4, c: 5 }

复制对象

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

深拷贝问题

针对深拷贝 (en-US), 需要使用其他办法,因为 Object.assign() 只复制属性值。

假如源对象是一个对象的引用,它仅仅会复制其引用值。

function test() {
   
  'use strict';

  let obj1 = {
    a: 0 , b: {
    c: 0}};
  let obj2 = Object.assign({
   }, obj1);
  console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}

  obj1.a = 1;
  console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 0}}
  console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}

  obj2.a = 2;
  console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 0}}
  console.log(JSON.stringify(obj2)); // { "a": 2, "b": { "c": 0}}

  obj2.b.c = 3;
  console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 3}}
  console.log(JSON.stringify(obj2)); // { "a": 2, "b": { "c": 3}}

  // Deep Clone
  obj1 = {
    a: 0 , b: {
    c: 0}};
  let obj3 = JSON.parse(JSON.stringify(obj1));
  obj1.a = 4;
  obj1.b.c = 4;
  console.log(JSON.stringify(obj3)); // { "a": 0, "b": { "c": 0}}
}

test();

合并对象

const o1 = {
    a: 1 };
const o2 = {
    b: 2 };
const o3 = {
    c: 3 };

const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.

合并具有相同属性的对象

const o1 = {
    a: 1, b: 1, c: 1 };
const o2 = {
    b: 2, c: 2 };
const o3 = {
    c: 3 };

const obj = Object.assign({
   }, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

属性会被后续参数中具有相同属性的其他对象覆盖。

拷贝 Symbol 类型属性

const o1 = {
    a: 1 };
const o2 = {
    [Symbol('foo')]: 2 };

const obj = Object.assign({
   }, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]

原型链上的属性和不可枚举属性不能被复制

const obj = Object.create({
    foo: 1 }, {
    // foo is on obj's prototype chain.
  bar: {
   
    value: 2  // bar is a non-enumerable property.
  },
  baz: {
   
    value: 3,
    enumerable: true  // baz is an own enumerable property.
  }
});

const copy = Object.assign({
   }, obj);
console.log(copy); // { baz: 3 }

基本类型会被包装为对象

const v1 = 'abc';
const v2 = true;
const v3 = 10;
const v4 = Symbol('foo');

const obj = Object.assign({
   }, v1, null, v2, undefined, v3, v4);
// Primitives will be wrapped, null and undefined will be ignored.
// Note, only string wrappers can have own enumerable properties.
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

异常会打断后续拷贝任务

const target = Object.defineProperty({
   }, 'foo', {
   
  value: 1,
  writable: false
}); // target.foo is a read-only property

Object.assign(target, {
    bar: 2 }, {
    foo2: 3, foo: 3, foo3: 3 }, {
    baz: 4 });
// TypeError: "foo" is read-only
// The Exception is thrown when assigning target.foo

console.log(target.bar);  // 2, the first source was copied successfully.
console.log(target.foo2); // 3, the first property of the second source was copied successfully.
console.log(target.foo);  // 1, exception is thrown here.
console.log(target.foo3); // undefined, assign method has finished, foo3 will not be copied.
console.log(target.baz);  // undefined, the third source will not be copied either.

拷贝访问器

const obj = {
   
  foo: 1,
  get bar() {
   
    return 2;
  }
};

let copy = Object.assign({
   }, obj);
console.log(copy);
// { foo: 1, bar: 2 }
// The value of copy.bar is obj.bar's getter's return value.

// This is an assign function that copies full descriptors
function completeAssign(target, ...sources) {
   
  sources.forEach(source => {
   
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
   
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {
   });

    // By default, Object.assign copies enumerable Symbols, too
    Object.getOwnPropertySymbols(source).forEach(sym => {
   
      let descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
   
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

copy = completeAssign({
   }, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }
相关文章
|
7月前
|
JavaScript 前端开发 索引
JavaScript与Object C的区别
JavaScript与Object C的区别
39 1
|
JavaScript 前端开发
JavaScript 使用对象字面量创建对象、使用new Object创建对象
JavaScript 使用对象字面量创建对象、使用new Object创建对象
146 0
|
7月前
|
缓存 前端开发 JavaScript
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)
|
7月前
|
JavaScript 前端开发 测试技术
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)
理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(上)
|
7月前
|
存储 JavaScript 前端开发
【JavaScript】<面向对象Object>函数方法&对象创建&原型对象&作用域解析
【1月更文挑战第17天】【JavaScript】<面向对象Object>函数方法&对象创建&原型对象&作用域解析
|
7月前
|
JavaScript 前端开发
原生JavaScript JS导出blob后台文件流xlsx、xls文件自动下载(且规避乱码),解决导出Excel文件里面有[object Object]。
原生JavaScript JS导出blob后台文件流xlsx、xls文件自动下载(且规避乱码),解决导出Excel文件里面有[object Object]。
|
Web App开发 JSON JavaScript
JavaScript对象类型之Array及Object
JavaScript对象类型之Array及Object
86 0
|
存储 前端开发 JavaScript
前端祖传三件套JavaScript的对象之常用引用类型的Object
在 JavaScript 中,对象是一种非常重要的数据类型,它可以用来存储和处理复杂的数据结构。在对象中,引用类型 Object 是一种常用的类型,它可以用来封装各种不同类型的数据,并提供了许多方便的方法来操作这些数据。本文将介绍 Object 引用类型的概念、使用方法以及一些常见的注意事项。
106 0
|
存储 JavaScript 前端开发
web前端-JavaScript中的对象(Object)
web前端-JavaScript中的对象(Object)
118 0
|
JavaScript 前端开发
深入理解JavaScript- Object(对象)
深入理解JavaScript- Object(对象)
122 0
深入理解JavaScript- Object(对象)