1. Когда дело доходит до глубокой и поверхностной копии JavaScript, она должна начинаться с ее «источника» — двух основных типов данных JavaScript (базовый тип данных и ссылочный тип данных).
- Особенности базовых типов данных: данные хранятся непосредственно в стеке.
- Характеристики ссылочного типа данных: ссылка на объект хранится в стеке, а реальные данные хранятся в куче памяти.
- Основные типы данных: String, Number, Boolean, Null, Undefined, Symbol, BigInt.
- Тип ссылочных данных: Объект.
2. Разница между глубоким и поверхностным копированием.
- Неглубокое копирование: копируйте только указатель на объект, а не сам объект, а старый и новый объекты по-прежнему используют одну и ту же память.
- Глубокая копия: будет создан идентичный объект.Новый объект и исходный объект не используют общую память, и изменение нового объекта не изменит исходный объект.
(Примечание. В узком смысле глубокое и поверхностное копирование предназначено только для ссылочных типов данных, а базовые типы данных — это только операции присваивания)
3. Оригинальный метод в JavaScript реализует ограниченную «глубокую и поверхностную копию».
- Object.assign({}, obj): когда obj является однослойным объектом, Object.assign() в это время может реализовать «глубокое копирование», а когда obj является многослойным объектом, то Object.assign({ }, obj) может реализовать только «поверхностное копирование».
-
JSON.parse(JSON.stringify(xxx)): эта комбинация может реализовать глубокую копию общих объектов (кроме функции, Symbol(), undefined); при реализации функции Symbol(), undefined, это приведет к потере данных, поэтому его нельзя назвать идеальной глубокой копией.
4. Затем, если вы хотите реализовать полнофункциональную и высокосовместимую глубокую копию на JS, то вам придется написать функцию глубокой копии самостоятельно (PS: Это также обязательный вопрос на собеседовании, и вам будет предложено описать основная идея реализации если не писать от руки).
Основная идея реализации: с помощью рекурсивного мышления проходить объекты и массивы до тех пор, пока они не станут всеми базовыми типами данных, а затем копировать их, то есть глубокое копирование.
// 深拷贝:对对象内部进行深拷贝,支持 Array、Date、RegExp、DOM
function deepCopy(params) {
// 如果不是对象则退出(可停止递归)
if (typeof params !== 'object') return;
// 深拷贝初始值:对象/数组
let newObj = (params instanceof Array) ? [] : {};
// 使用 for-in 循环对象属性(包括原型链上的属性)
for (let i in params) {
// 只访问对象自身属性
if (params.hasOwnProperty(i)) {
// 当前属性还未存在于新对象中时
if (!(i in newObj)) {
if (params[i] instanceof Date) {
// 判断日期类型
newObj[i] = new Date(params[i].getTime());
} else if (params[i] instanceof RegExp) {
// 判断正则类型
newObj[i] = new RegExp(params[i]);
} else if ((typeof params[i] === 'object') && params[i].nodeType === 1) {
// 判断 DOM 元素节点
let domEle = document.getElementsByTagName(params[i].nodeName)[0];
newObj[i] = domEle.cloneNode(true);
} else {
// 当元素属于对象(排除 Date、RegExp、DOM)类型时递归拷贝
newObj[i] = (typeof params[i] === 'object') ? deepCopy(params[i]) : params[i];
}
}
}
}
return newObj;
}