jQuery 实现深浅拷贝 :
1. js实现 深浅拷贝
在复制一个数据类型的时候(特指复杂数据类型, 数组或者对象)
在 JS 内, 对于 “复制” 有三个级别 :
赋值
浅拷贝
深拷贝
1.1 赋值 :
简单的地址复制
使用 赋值符号( = ) 进行的操作
对于基本数据类型, 赋值之后两个变量之间没有任何关系
对于复杂数据类型, 赋值之后两个变量操作同一个数据存储空间
obj存的是地址
// 1. 赋值
let n1 = 5
// 把 n1 的值赋值给了 n2
let n2 = n1
console.log(n1, n2) // 5 5
n2 = 10
console.log(n1, n2) // 5 10
const o1 = { name: 'Jack' }
// 进行赋值操作, 把 o1 的值赋值给了 o2
// 因为 o1 这个变量内存储的是指向一个 对象数据类型 的空间地址
// 赋值的过程中, 就是把 o1 存储的地址赋值给了 o2
// 所以给到 o2 的依旧是一个 地址
// 从此以后 o1 和 o2 操作一个对象存储空间
const o2 = o1
console.log(o1, o2)
// 使用任意一个变量名修改对象空间内的成员
o2.name = 'Rose'
console.log(o1, o2)
1.2 浅拷贝 :
=> 创建一个和原先数据结构一模一样的数据结构
假如原先是个数组数据类型, 那么就新创建一个数组
假如原先是个对象数据类型, 那么就新创建一个对象
=> 通过 for in 循环去遍历原先数据结构
把里面的每一个数据分别在新的数据结构中复制一份
对于一维数据结构有效
如果是多维数据结构,没有意义 , 那么从第二维度开始, 依旧是操作同一个存储空间
// 2. 浅拷贝
const o1 = { name: 'Jack', age: 18, info: { height: 180 } }
// 2-1. 创建一个和原先数据结构一模一样的结构
const o2 = {}
// 2-2. 循环遍历原始数据结构
for (const key in o1) {
// 2-3. 分别在新的数据结构中进行赋值
// 在进行 for in 遍历的时候
// 在这里, 当 key === info 的时候
// o1[key] 存储的也是一个地址
// o2[key] 就是把 o1[key] 存储的地址复制了一份过去
// 从此以后, o1 和 o2 虽然是两个数据空间
// 但是 o1.info 和 o2.info 操作的是一个数据空间
// o2.info = o1.info
// 因为 info 内存储的是一个 地址
// 赋值以后, o2.info 和 o1.info 存储的是同一个地址
o2[key] = o1[key]
}
// 此时 o1 和 o2 不是一个对象存储空间
// 只是长得一模一样的两个对象存储空间
// 用任意一个区操作的时候, 另外一个不会改变
console.log(o1, o2)
// 修改
o2.name = 'Rose'
o2.age = 20
console.log(o1, o2)
// 修改第二维度 info 内的数据
o2.info.height = 200
console.log(o1, o2)
知识点扩展 :
// 准确的判断所有数据类型
// 语法: Object.prototype.toString.call(你要判断的数据类型)
// 返回值: 该数据类型的 类型字符串 '[object 类型]'
console.log(Object.prototype.toString.call({})) // Object
console.log(Object.prototype.toString.call([])) // Array
console.log(Object.prototype.toString.call(123)) // Number
console.log(Object.prototype.toString.call('123')) // String
console.log(Object.prototype.toString.call(true)) // Boolean
console.log(Object.prototype.toString.call(null)) // Null
console.log(Object.prototype.toString.call(undefined))// Undefined
console.log(Object.prototype.toString.call(/^$/)) // RegExp
console.log(Object.prototype.toString.call(new Date()))// Date
console.log(Object.prototype.toString.call(function () {}))//Function
1.3 深拷贝 :
=> 不停地重复浅拷贝的工作
=> 复制出一份完全一模一样的数据结构
=> 不管多少维度的数据结构, 都能完整独立的复制过来
=> 实现方式:
使用 递归 的方式进行逐层数据结构的 遍历数据并赋值
当我循环遍历的时候, 如果碰到的还是复杂数据类型
那么就递归进行遍历
// 3. 深拷贝
const o1 = {
name: 'Jack',
age: 18,
info: {
weight: 180,
height: 180,
desc: {
msg: '这个人很懒, 什么都没有留下!'
}
},
hobby: ['吃饭', '睡觉', ['篮球', '足球']]
}
const o2 = {}
// 3-1. 书写函数来完成(递归函数)
// 使用递归的方式进行深拷贝
function deepCopy(o2, o1) {
// 做: 把 o1 内的所有数据全部拷贝到 o2 内部
// console.log(o1, o2)
//3-2. 直接循环遍历 o1 数据
for (let key in o1) {
// console.log(key);
// 判断, 如果是 对象数据类型 或者 数组数据类型, 不进行赋值
// 否则, 才进行赋值
// 如果 o1[key] 是一个对象数据类型
// o2[key] 也要创建为一个对象数据类型
// 如果 o1[key] 是一个数组数据类型
// o2[key] 也要创建为一个数组数据类型
// 如果 o1[key] 是一个基本数据类型
// o2[key] 直接赋值
if (Object.prototype.toString.call(o1[key]) === '[object Object]') {
// 是对象
// console.log('o1[key] 是一个对象数据类型 : ', key)
o2[key] = {}
// 在这个位置, o1[key] 是一个对象数据类型
// o2[key] 也是一个数据类型
// o1[key] 里面的每一个数据复制一份到 o2[key]
deepCopy(o2[key], o1[key])
} else if (o1[key].constructor === Array) {
// 是数组
// console.log('o1[key] 是一个数组数据类型 : ', key)
o2[key] = []
// 把 o1[key] 内部的所有数据放在 o2[key] 内
deepCopy(o2[key], o1[key])
} else {
// console.log('o1[key] 是一个基本数据类型 : ', key)
// 直接复制
o2[key] = o1[key]
}
}
}
// 将来使用的时候
deepCopy(o2, o1)
console.log(o1, o2)
// 修改数据
o2.info.desc.msg = 'hello world'
1.4 深拷贝 - 方案2
只能是在 对象 和 数组 数据结构中使用
不能有函数
利用 json 格式字符串
4-1. 把源数据转换成 json 格式字符串
4-2. 把 json 格式字符串转换回 js 数据类型
// 4. 深拷贝 - 方案2
const o1 = { name: 'Jack', age: 18, info: { weight: 180, height: 180, desc: { msg: '你好 世界' } }, hobby: [ '吃饭', '睡觉' ] }
console.log(o1)
// 把 o1 转换成 json 格式字符串
// 现在的 jsonStr 就是基本数据类型
const jsonStr = JSON.stringify(o1)
console.log(jsonStr)
// 把 s 转换成一个 JS 的对象格式
const o2 = JSON.parse(jsonStr)
console.log(o2)
// 修改
o2.info.desc.msg = 'hello world'
console.log(o1, o2)
2. jQuery 实现深浅拷贝的方法 $.extend( ):
const o1 = {
name: 'Jack',
age: 18,
info: {
weight: 180,
height: 180,
desc: {
msg: '这个人很懒, 什么都没有留下!',
title: '你好 世界'
}
},
hobby: [ '吃饭', '睡觉', [ '篮球', '羽毛球', '足球' ] ]
}
2.1 浅拷贝 :
=> 语法: $.extend(对象1, 对象2, 对象3, …)
=> 作用: 把从 对象2 开始的所有对象内的数据进行浅拷贝到 对象1 内
=> 实现的是浅拷贝
// 1. 实现浅拷贝
// 把 o1 内的所有数据进行浅拷贝到 o2 身上
let o2 = {}
$.extend(o2, o1)
console.log(o1, o2)
// 修改一下数据
o2.name = 'Rose'
// 第二维度修改
o2.info.height = 200
console.log(o1, o2)
2.2 深拷贝:
=> 语法: $.extend(true, 对象1, 对象2, 对象3, …)
=> 作用: 把从 对象2 开始的所有对象内的数据进行深拷贝到 对象1 内
=> 实现的是深拷贝
// 2. 实现深拷贝
let o2 = {}
$.extend(true, o2, o1)
// console.log(o1, o2)
// 修改
o2.name = 'Tom'
o2.info.height = 250
o2.info.desc.msg = '这个人更懒'
console.log(o1, o2)
赋值,改一个,另一个也跟着变
浅拷贝,一维改一个,另一个独立的,不变
深拷贝,两个完全独立,随便改,无所谓
————————————————
版权声明:本文为优快云博主「533_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/qq_14993591/article/details/120737206