概述
关于赋值
赋值,即直接将变量相等,=,此时对于这两个变量来讲,指向了同个内存地址,所以,内存地址指向的内容一旦改变就会同步改变
关于 js 变量类型
基本数据类型: Number, Boolean, String, Symbol, null, undefined
引用类型: Object,诸如 array, function, object
关于浅拷贝
浅拷贝的理解就是两个变量的内存地址是不一样的,但对于不同类型的变量是有区别的:
基本数据类型: 一个变量的更改不会引起另一个变量的更改
引用类型:一个变量的内容更改会引起另一个变量的更改
const a = [{aa: 1}]
var b = a.map(item => { // 因为此时item是一个对象,所以是直接更改item.aa也会影响a
item.aa = 2
return item
})
console.log(b) // b: {aa: 2}
console.log(a) // a: {aa: 2}
实现一个浅拷贝
Object.assign
利用 Object.assign 能进行浅拷贝,仅拷贝一级 key 的 value 值,如果你对原值进行二级以上的 value 值的拷贝,则两个变量都会同时受到影响
展开运算符
var a = {aa: 1}
var b = {...a}
深拷贝概念
浅拷贝的理解就是两个变量的内存地址是不一样的,一般更加应用于引用类型
引用类型:一个变量的内容更改不会引起另一个变量的更改,因为内容对应的内存地址不一样,所以取到的值也就不一样
实现一个深拷贝
简单版
var obj = {a: 1}
function clone(origin) {
return JSON.parse(JSON.stringify(origin))
}
var copy = clone(obj)
copy.a = 2
console.log(obj)
console.log(copy)
打印出来的结果是:
可以看到两者不受影响了
上述方法存在问题,比如
原对象有函数,是不能被序列化的
原对象有 value 是 undefined 的,也是不能被序列化的
原对象有正则的,不能被序列化
比如:
var obj = {
a: 1,
b: undefined,
say: function() {
console.log(this.a)
}
}
function clone(origin) {
return JSON.parse(JSON.stringify(origin))
}
var copy = clone(obj)
copy.a = 2
console.log(obj)
console.log(copy)
可见:第二个对象丢失了 b,say 等 key
进阶版+1
利用递归所有的 key,手动赋值给新对象
var obj = {
a: 1,
b: undefined,
c: { cc: 1 },
say: function () {
console.log(this.a);
},
};
function clone(origin) {
let newValue = new origin.constructor();
for (let key in origin) {
if (typeof origin[key] === 'object') {
debugger;
newValue[key] = clone(origin[key]);
} else {
newValue[key] = origin[key];
}
}
return newValue;
}
var copy = clone(obj);
copy.c.cc = 2;
console.log(obj);
console.log(copy);
进阶版+2
上述存在以下问题:
边界条件判断
循环引用
循环引用见以下例子:
var obj = {
a: 1,
};
var obj2 = {
obj: obj,
};
obj.obj2 = obj2;
function clone(origin) {
let newValue = new origin.constructor();
for (let key in origin) {
if (typeof origin[key] === 'object') {
newValue[key] = clone(origin[key]);
} else {
newValue[key] = origin[key];
}
}
return newValue;
}
var copy = clone(obj);
console.log(obj);
console.log(copy);
js 达到最大调用栈了,死循环了
解决思路:
利用缓存,可以将已经存在的引用直接返回。同时,可以利用 weakmap 解决内存泄露的问题
var obj = {
a: 1,
};
var obj2 = {
obj: obj,
};
obj.obj2 = obj2;
// stack为缓存,是一个weapMap实例
function clone(origin, stack = new WeakMap()) {
let newValue = new origin.constructor();
if (stack.has(origin)) { // 如果缓存已存在,直接返回
return stack.get(origin);
}
stack.set(origin, newValue); // 缓存中不存在,则新增一条记录
for (let key in origin) {
if (typeof origin[key] === 'object') {
newValue[key] = clone(origin[key], stack);
} else {
newValue[key] = origin[key];
}
}
return newValue;
}
var copy = clone(obj);
console.log(obj);
console.log(copy);
最后,完整代码:
var obj = {
a: 1,
};
var obj2 = {
obj: obj,
};
obj.obj2 = obj2;
function clone(origin, stack = new WeakMap()) {
if (!origin) {
return origin;
}
if (obj instanceof Date) {
// 增加Date类型的copy
return new Date(origin);
}
if (obj instanceof RegExp) {
// 增加正则类型的copy
return new RegExp(origin);
}
let newValue = new origin.constructor();
if (stack.has(origin)) {
return stack.get(origin);
}
stack.set(origin, newValue);
for (let key in origin) {
if (typeof origin[key] === 'object') {
newValue[key] = clone(origin[key], stack);
} else {
newValue[key] = origin[key];
}
}
return newValue;
}
var copy = clone(obj);
console.log(obj);
console.log(copy);
lodash cloneDeep 关键源码分析
clone 用到的关键的 baseClone 函数
/**
* The base implementation of `clone` and `cloneDeep` which tracks
* traversed objects.
*
* @private
* @param {*} value The value to clone.
* @param {number} bitmask The bitmask flags.
* 1 - Deep clone
* 2 - Flatten inherited properties
* 4 - Clone symbols
* @param {Function} [customizer] The function to customize cloning.
* @param {string} [key] The key of `value`.
* @param {Object} [object] The parent object of `value`.
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
* @returns {*} Returns the cloned value.
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
// Check for circular references and return its corresponding clone.
// 这里同样用到缓存
stack || (stack = new Stack());
const stacked = stack.get(value);
if (stacked) {
return stacked;
}
stack.set(value, result);
const props = isArr ? undefined : keysFunc(value);
// 开始遍历递归
arrayEach(props || value, (subValue, key) => {
if (props) {
key = subValue;
subValue = value[key];
}
// Recursively populate clone (susceptible to call stack limits).
assignValue(
result,
key,
baseClone(subValue, bitmask, customizer, key, value, stack)
);
});
return result;
}
更多精彩文章可以看我的博客,如有错误,欢迎指正,共同进步
最后
以上就是动人唇彩为你收集整理的面试题-关于深拷贝浅拷贝的全部内容,希望文章能够帮你解决面试题-关于深拷贝浅拷贝所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复