此文首发于 https://lijing0906.github.io
上周在总结赋值和深浅拷贝的时候提到了Object.assign
这种浅拷贝方式。这周谈谈它的原理以及实现方式。
浅拷贝Object.assign
上篇文章有讲到它的定义和用法,主要是将所有可枚举属性的值从一个或多个源对象中复制到目标对象,同时返回目标对象。
语法如下:
Object.assign(target, ...source)
其中target
是目标对象,...source
是源对象,可以是一个或多个,返回修改后的目标对象。
如果目标对象和源对象具有相同属性,则目标对象的该属性将会被源对象的相同属性覆盖,后来的源对象的属性将会类似地覆盖早先的属性。
示例1
我们知道浅拷贝就是拷贝对象的第一层的基本类型值,以及第一层的引用类型地址。
// 第一步
let a = {
name: "Kitty",
age: 18
}
let b = {
name: "Jane",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let c = Object.assign(a, b);
console.log(c);
// {
// name: "Jane",
// age: 18,
// book: {title: "You Don't Know JS", price: "45"}
// }
console.log(a === c); // true
// 第二步
b.name = "change";
b.book.price = "55";
console.log(b);
// {
// name: "change",
// book: {title: "You Don't Know JS", price: "55"}
// }
// 第三步
console.log(a);
// {
// name: "Jane",
// age: 18,
// book: {title: "You Don't Know JS", price: "55"}
// }
1、第一步中,使用Object.assign
把源对象b中的属性复制到目标对象a中,把改变后的对象定义为c,可以看出b会替换掉a中相同的属性的值。上面的代码需要注意的是,返回对象c就是目标对象a。
2、第二步中,修改源对象b的基本类型值(name)和引用类型值(book)。
3、第三步中,浅拷贝之后目标对象a的基本类型值没有改变,但引用类型值被改变了,因为Object.assign
拷贝的是属性值,当属性值是一个指向对象的引用时,它拷贝的那个引用地址。
示例2
String
类型和Symbol
类型的属性都会被拷贝,而且不会跳过那些值为null
或undefined
的属性。
let a = {
name: "Jane",
age: 20
}
let b = {
b1: Symbol("Jane"),
b2: null,
b3: undefined
}
let c = Object.assign(a, b);
console.log(c);
// {
// name: "Jane",
// age: 20,
// b1: Symbol(Jane),
// b2: null,
// b3: undefined
// }
console.log(a === c); // true
Object.assign模拟实现
实现一个Object.assign
大致思路如下:
1、判断原生Object
是否支持该函数,如果不存在的话创建一个函数assign
,并使用Object.defineProperty
将该函数绑定到Object
上。
2、判断参数是否正确(目标对象不能为空,我们可以直接设置{}传递进去,但必须设置值)。
3、使用Object()
转成对象,并保存为to
,最后返回这个对象to
。
4、使用for..