【前端】JavaScript--浅拷贝与深拷贝
·
浅拷贝
复制基本类型和值
var a = 1;
b = a;
a = 2;
console.log(a, b);
2 1
深拷贝
对引用类型拷贝,会进行地址的拷贝

var a = { c: 1 };
b = a;
a.c = 2;
console.log(a.c, b.c);
2 2
浅拷贝的实现
function shallowClone(source) {
var target = {};
for (var i in source) {
if (source.hasObject(i)) {
target[i] == source[i];
}
}
return target;
}
上述代码相关:for in, Object.keys和Object.getOwnPropertyNames的区别
const linglingkwong = Object.create({ age: 30 });
Object.defineProperty(linglingkwong, 'sex', { value: 'female', enumerable: false });
linglingkwong[Symbol('partner')] = 'orm'; // symbol 用来表示唯一的、不可变的值
linglingkwong.own = 1;
// for-in
for (const k in linglingkwong)
console.log(k) // own age -- 只枚举
// Object.keys
console.log(Object.keys(linglingkwong)); // ['own'] -- 自身,可枚举
// Object.getOwnPropertyNames
console.log(Object.getOwnPropertyNames(linglingkwong)); // ['sex', 'own']
为什么会出现不同的结果?
上述对象 linglingkwong 中有三种属性
- 原型链
- 不可枚举
- Symbol
如何区分这三种属性呢?
JavaScript 中的 Object.create() 方法用于创建一个新对象,并指定该对象的原型。
即,age 是 linglingkwong 的原型。
const linglingkwong = Object.create({ age: 30 });
创建了一个空对象,它的原型指向 {age : 30}
{age : 30}创建了一个新的匿名对象,它有一个属性age,值为30。
Object.create(...)以这个匿名对象为原型,创建了一个新对象。
const linglingkwong = ... 将这个新对象赋值给 linglingkwong
即 age 为原型。
enumerable:true时,为可枚举。它是描述内部属性的。
Symbol是对象属性的属性,它表示该属性是唯一的。
由上述结果可知:
三种方式种只有 for-in 可以访问原型链。
当内部属性为不可枚举时,不能用for-in遍历到,也不能用Object.keys访问。
上述三种方法中,只有Object.getOwnPropertySymbols(obj) 可以访问Symbol属性。
深拷贝的实现
弱点:存在爆栈问题,循环引用问题
function clone(source) {
var target = {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
if (typeof source[i] === 'object') {
target[i] = clone(source[i]);
} else {
target[i] = source[i];
}
}
}
return target;
}
不过,上述代码中仍存在一些问题。
没有对参数做检验
函数需要校验参数,不是对象的话直接返回。
if (!isObject(source)) return source;
不过上述判断是否为对象的逻辑不严谨,如果遇到null,会误判成object。
因此,采用:
if (source == null || !isObject(source)) return source;
解决循环引用的问题
if (hash.has(source)) return hash.get(source);
没有考虑数组的兼容
需要区分数组和普通对象
const target = Array.isArray(source) ? [] : {};
hash.set (source, target);
for (const key of Reflect.ownKeys(source)){
target[key] = clone(source[key], hash);
}
一行代码的深拷贝
弱点:存在循环引用问题,爆栈问题
function cloneJSON(source) {
return JSON.parse(JSON.stringify(source));
}
破解循环引用
// 遍历uniqueList
function find(arr, item) {
for (let i = 0; i < arr.length; i++) {
if (arr[i].source === item) {
return arr[i]
}
}
return null;
}
function cloneForce(x) {
const uniqueList = []; // 用来去重
let root = {};
// 循环数组
const loopList = [
{
parent: root,
key: undefined,
data: x,
}
];
while (loopList.length) {
// 深度优先
const code = loopList.pop();
const parent = node.parent;
const key = node.key;
const data = node.data;
// 初始化赋值目标 key为undefined则拷贝到父元素,否则拷贝到子元素
let res = parent;
if (typeof key !== 'undefined') {
res = parent[key] = {};
}
let uniqueData = find(uniqueList, data);
// 数据已经存在
if (uniqueData) {
parent[key] = uniqueData.target;
break;
}
// 数据不存在
// 保存数据源 在拷贝数据中对应呃引用
uniqueList.push({
source: data,
target: res,
})
for (let k in data) {
if (data.hasOwnProperty(k)) {
if (typeof data[k] === 'object') {
// 下一次循环
loopList.push({
parent: res,
key: k,
data: data[k],
});
} else {
res[k] = data[k];
}
}
}
}
return root;
}
更多推荐



所有评论(0)