每天温习一个JS方法之Object.assign方法 第一天

1. Object.assign 描述

Object.assign() 方法将所有可枚举Object.propertyIsEnumerable() 返回 true)的自有Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象

1.1 语法

Object.assign(target, ...sources) // 返回合并后的target的对象
  • target

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

  • source

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

2. Object.assign 应用

2.1 基本示例

let target = {
    
     a: 1 };
let source = {
    
     b: 1, c: 1 };
const final = Object.assign(target, source);
console.log(final); // {a: 1, b: 1, c: 1}

// 我们输出target 看看
console.log(target); // {a: 1, b: 1, c: 1}

发现target的对象也变了,如何避免呢?深拷贝

let target = {
    
     a: 1 };
let source = {
    
     b: 1, c: 1 };
const final = Object.assign(JSON.parse(JSON.stringify(target)), source);
console.log(final);// {a: 1, b: 1, c: 1}

console.log(target);// {a: 1} 这样就不会改变target了

2.2 合并对象中 存在相同属性的情况

// 一个 source 时
let target = {
    
     a: 1 };
let source = {
    
     a: 100, b: 1, c: 1 };
const final = Object.assign(target, source);
console.log(final); // {a: 100, b: 1, c: 1}

// 两个source 时
let target = {
    
     a: 1 };
let source = {
    
     a: 100, b: 1, c: 1 };
let source1 = {
    
     c: 100, d: 1 };
const final = Object.assign(target, source, source1);
console.log(final); // {a: 100, b: 1, c: 100, d: 1}

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

2.3 赋值引用问题

let source = {
    
    
    a: 1,
    b: {
    
    
        c: 1,
    },
};
const final = Object.assign({
    
    }, source);
console.log(final); // { a: 1, b: { c: 1 } }
console.log(source);// { a: 1, b: { c: 1 } }

source.a = 2;
console.log(final);// { a: 1, b: { c: 1 } }  不变
console.log(source);// { a: 2, b: { c: 1 } } 变了

source.b.c = 2;
console.log(final); // { a: 1, b: { c: 2 } }  变了
console.log(source);// { a: 2, b: { c: 2 } }  变了

可以发现,源对象是一个对象的引用,它仅仅会复制其引用值,若源对象内嵌一个对象,且在源对象对其值进行改变,合并后的值也会发生改变。

如何避免呢?采用JSON.parse(JSON.stringify(Object.assign({}, source))即可

2.4 异常会打断后续拷贝任务

let target = Object.defineProperty({
    
    }, 'a', {
    
    
	value: 1,
	writable: false, // 不可写
});
try {
    
    
	Object.assign(target, {
    
     b: 1 }, {
    
     a: 3 }, {
    
     c: 1 });
} catch (e) {
    
    
	console.log(e);
}
console.log(target.b); // 1
console.log(target.a); // 1
console.log(target.c); // undefined

如果赋值期间出错,例如如果属性不可写,则会抛出 TypeError;如果在抛出异常之前添加了任何属性,则会修改 target 对象

2.5 Object.assign() 不会在 source 对象值为 nullundefined 时抛出错误

const final = Object.assign({
    
    }, {
    
     a: 1 }, undefined, {
    
     b: 1 }, null);
console.log(final); // {a: 1, b: 1}

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

//摘自MDN
const obj = Object.create(
	{
    
     foo: 1 },
	{
    
    
	// foo 在obj的原型链上
	bar: {
    
    
		value: 2, // bar 是一个不可枚举属性
	},
	baz: {
    
    
		value: 3,
		enumerable: true, // baz 是一个枚举属性
		},
	}
);

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

2.7 基本类型会被包装为对象

const obj = Object.assign({
    
    }, 'happy');
console.log(obj); // {0: 'h', 1: 'a', 2: 'p', 3: 'p', 4: 'y'}

const obj = Object.assign({
    
    }, 'happy', 'good', true, 10);
console.log(obj); // {0: 'g', 1: 'o', 2: 'o', 3: 'd', 4: 'y'} 注意与上面输出的前四个区别

注:只有字符串可以有自己的可枚举属性。

2.8 拷贝访问器

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

let copy = Object.assign({
    
    }, obj);
console.log(copy); // { foo: 1, bar: 2 }

// 这是一个复制完整描述符的赋值函数
function completeAssign(target, ...sources) {
    
    
  sources.forEach(source => {
    
    
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
    
    
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {
    
    });

    // 默认情况下,对象,也分配可枚举符号的副本
    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 } }

3. 结尾

参考自MDN
每天温习一个JS方法之Object.assign方法 第一天

猜你喜欢

转载自blog.csdn.net/News777/article/details/127106288