学习了coderwhy的JavaScript高级语法视频课的笔记
如有错误或者不合适的地方,敬请见谅,欢迎指出和拓展,谢谢各位了
- 对象相互赋值的一些关系,分别包括:
- 引入的赋值:指向同一个对象,相互之间会影响;
- 对象的浅拷贝:只是浅层的拷贝,内部引入对象时,依然会相互影响;
- 对象的深拷贝:两个对象不再有任何关系,不会相互影响。
- 前面我们已经可以通过一种方法来实现深拷贝了——JSON.stringify和JSON.parse:
- 这种深拷贝的方式其实对于函数、Symbol等是无法处理的;
- 并且如果存在对象的循环引用,也会报错的。
const obj = {
name: 'aaa',
friend: {
name: 'bbb'
},
fn: function () {
console.log('函数')
}
}
const newObj = JSON.parse(JSON.stringify(obj))
obj.name = 'AAA'
console.log(obj) //{ name: 'AAA', friend: { name: 'bbb' }, fn: [Function: fn] }
console.log(newObj) //{ name: 'aaa', friend: { name: 'bbb' } }
自定义深拷贝函数:
1. 深拷贝函数 — 基本实现
function isObject(val) {
const valType = typeof val
return valType !== null && valType === 'object'
}
function deepClone(obj) {
// 调用isObject(),然后判断值取反,不是object对象,则直接return值
if (!isObject(obj)) {
return obj
}
const newObj = {}
for (const key in obj) {
// 递归调用,解决最外层{}属性的值为对象的深拷贝问题
newObj[key] = deepClone(obj[key])
}
return newObj
}
const obj = {
name: 'aaa',
friend: {
name: 'bbb'
},
fn: function () {
console.log('函数')
}
}
const newObj = deepClone(obj)
obj.name = 'AAA'
obj.friend.name = 'BBB'
console.log(obj)
console.log(newObj)
2. 深拷贝函数 — 其它数据类型
const { debug } = require('console')
function isObject(val) {
const valType = typeof val
return valType !== null && valType === 'object'
}
function deepClone(obj) {
// // 判断是否是一个Set类型
if (obj instanceof Set) {
return new Set([...obj])
}
// 判断是否是一个Map类型
if (obj instanceof Map) {
return new Map([...obj])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof obj === 'Symbol') {
return Symbol(obj.directives)
}
// 调用isObject(),然后判断值取反,不是object对象,则直接return值
if (!isObject(obj)) {
return obj
}
// 解决属性数组的问题
const newObj = Array.isArray(obj) ? [] : {}
for (const key in obj) {
// 递归调用,解决最外层{}属性的值为对象的深拷贝问题
newObj[key] = deepClone(obj[key])
}
// 对Symbol的key进行特殊的处理
const objSymbolKeys = Object.getOwnPropertySymbols(obj)
for (const key of objSymbolKeys) {
newObj[key] = deepClone(obj[key])
}
return newObj
}
const s1 = Symbol('xxx')
const s2 = Symbol('yyy')
const obj = {
name: 'aaa',
friend: {
name: 'bbb'
},
fn: function () {
console.log('函数')
},
arr: ['a', 'b', 'c'],
[s1]: 'ccc',
[s2]: s2,
set: new Set(['a', 'b', 'c']),
map: new Map([
['a', 'aaa'],
['b', 'bbb'],
['c', 'ccc']
])
}
const newObj = deepClone(obj)
obj.name = 'AAA'
obj.friend.name = 'BBB'
console.log(obj)
console.log(newObj)
3. 深拷贝函数 — 循环引用
function isObject(val) {
const valType = typeof val
return valType !== null && valType === 'object'
}
// 设置为全局的话,每一次调用deepClone(obj)都会储存一份
// const map = new WeakMap()
function deepClone(obj, map = new WeakMap()) {
// // 判断是否是一个Set类型
if (obj instanceof Set) {
return new Set([...obj])
}
// 判断是否是一个Map类型
if (obj instanceof Map) {
return new Map([...obj])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof obj === 'Symbol') {
return Symbol(obj.directives)
}
// 调用isObject(),然后判断值取反,不是object对象,则直接return值
if (!isObject(obj)) {
return obj
}
if (map.has(obj)) {
return map.get(obj)
}
// 解决属性数组的问题
const newObj = Array.isArray(obj) ? [] : {}
// 保存一份深拷贝的newObj对象
// newObj对象每一次递归调用都会更新一次值,但是key值不变,所以每次都是覆盖进行更新
map.set(obj, newObj)
for (const key in obj) {
// 递归调用,解决最外层{}属性的值为对象的深拷贝问题
newObj[key] = deepClone(obj[key], map)
}
// 对Symbol的key进行特殊的处理
const objSymbolKeys = Object.getOwnPropertySymbols(obj)
for (const key of objSymbolKeys) {
newObj[key] = deepClone(obj[key], map)
}
return newObj
}
const s1 = Symbol('xxx')
const s2 = Symbol('yyy')
const obj = {
name: 'aaa',
friend: {
name: 'bbb'
},
fn: function () {
console.log('函数')
},
arr: ['a', 'b', 'c'],
[s1]: 'ccc',
[s2]: s2,
set: new Set(['a', 'b', 'c']),
map: new Map([
['a', 'aaa'],
['b', 'bbb'],
['c', 'ccc']
])
}
// 循环引用
obj.info = obj
const newObj = deepClone(obj)
obj.name = 'AAA'
obj.friend.name = 'BBB'
console.log(obj)
console.log(newObj)
console.log(obj.info.info)
console.log(newObj.info.info)