Глубокая копия JavaScript и мелкая копия

внешний интерфейс программист JavaScript регулярное выражение

предисловие

В работе вы часто будете сталкиваться с ситуацией оперирования массивами и объектами, обязательно будете "бэкапить" исходные массивы и объекты.
Когда вы на самом деле работаете с ним, вы обнаруживаете, что резервная копия также изменилась.В это время вы в замешательстве, почему это, разве это уже не резервное копирование, и как также изменятся резервные массивы и объекты.
Если вы не совсем понимаете принцип копирования, эта статья может вам немного помочь.

тип данных JavaScript

базовый тип данных

string,number,null,undefined,boolean,symbol(Новое в ES6) Значение переменной хранится в памяти стека, и к значению переменной можно получить прямой доступ и изменить его.
Нет копии базового типа данных, поэтому, например, вы не можете изменить значение значения 1.

тип ссылки

Object Function RegExp Math Date Значение представляет собой объект, хранящийся в куче памяти.
Переменная, хранящаяся в памяти стека, является указателем на адрес, соответствующий памяти кучи.
При доступе к ссылочному типу указатель адреса объекта должен быть сначала извлечен из стека, а затем требуемые данные должны быть извлечены из кучи памяти.

мелкая копия

Почему объект массива резервной копии также изменяется?Здесь речь идет о «резервной копии», которую вы используете, на самом деле неглубокая копия

Простая эталонная копия

var a = [1,2,3,4];
var b = a;
a[0] = 0;
console.log(a,b);


Вы можете видеть, что массив a напрямую присваиваетсяb,a,bСсылка на самом деле является адресом объекта, пока значение адреса изменяется,a,bАдрес кучи, на который указывает указатель стековой памяти, также изменится.Эта ссылочная копия только добавляет указатель на стековую память переменной, что не имеет большого значения.

concat, часть массива, присвоить копию объекта

тот же пример

var a = [1,2,3,4];
var b = a.concat();
a[0] = 0;
console.log(a,b);


массив в это времяa[0]значение становится0,bМассив остается неизменным, и некоторые студенты спрашивали, не является ли это глубокой копией.

и да и нет,Array.prototype.sliceа такжеArray.prototype.concat выглядит как глубокая копия, но на самом деле это поверхностная копия

var a = [1,2,[3,4],{name:'ccy'}];
var b = a.concat();
a[3].name = 'hs';
console.log(a[3],b[3]);

 

когда массивaсодержит предметы, Array.prototype.sliceа такжеArray.prototype.cancatОбъекты в скопированном массиве по-прежнему используют один и тот же адрес памяти, поэтому это, по сути, поверхностная копия.

Object.assignПринцип тот же (ибо свойства объекта все базовые типы, его можно рассматривать как глубокую копию)

var a = {age:18,name:'ccy',info:{address:'wuhan',interest:'playCards'}};
var b = Object.assign(a);
a.info.address = 'shenzhen';
console.log(a.info,b.info);


Как сделать глубокую копию объекта, пожалуйста, держите очки.

Напишите функцию глубокого копирования самостоятельно

var clone = function(obj){
        var construct = Object.prototype.toString.call(obj).slice(8,-1);
        var res;
        if(construct === 'Array'){
            res = [];
        }else if(construct === 'Object'){
            res = {}
        }
        for(var item in obj){
            if(typeof obj[item] === 'object'){
                res[item] = clone(obj[item]);
            }else{
                res[item] = obj[item];
            }
        }
        return res;
    };

На первый взгляд кажется, что он может решить проблему, заключающуюся в том, что свойство объекта является объектом, и его можно обходить до тех пор, пока свойство не станет базовым типом;

Но подумайте хорошенько, если есть взаимные ссылки между свойствами объекта, будет бесконечный цикл. Вы можете добавить еще одно суждение.Если атрибут объекта ссылается на указатель объекта, он выйдет из текущего цикла.

глубокая копия

Глубокая копия может полностью устранить недостатки мелкой копии, повторно открывая блок адресов, базовое значение типа атрибутов из глубокой копии такое же.

Встроенные объекты глубоко копируют JSON

JSONObject — это новый тип, представленный в ES5 (поддерживаются браузеры IE8+),JSONобъектparseметод может бытьJSONДесериализовать строку вJSобъект,stringifyметод сериализации объектов JS вJSONString, с помощью этих двух методов также можно получить глубокую копию объекта.

var a = {age:1,name:'ccy',info:{address:'wuhan',interest:'playCards'}};
var b = JSON.parse(JSON.stringify(a));
a.info.address = 'shenzhen';
console.log(a.info,b.info);


 JSON Может обрабатывать общие объекты для глубокого копирования, но не может обрабатывать такие объекты, как функции и регулярки.

Пользовательская функция глубокого копирования

Мы можем снова оптимизировать функцию пользовательского копирования

var clone = function(obj){
        function getType(obj){
            return Object.prototype.toString.call(obj).slice(8,-1);
        }
        function getReg(a){
            var c = a.lastIndexOf('/');
            var reg = a.substring(1,c);
            var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '\w': '\\w', '\s': '\\s', '\d': '\\d'};
            for(var i in escMap){
                if(reg.indexOf(i)){
                    reg.replace(i,escMap[i]);
                }
            }
            var attr = a.substring(c+1);
            return new RegExp(reg, attr);
        }
        var construct = getType(obj);
        var res;
        if(construct === 'Array'){
            res = [];
        }else if(construct === 'Object'){
            res = {}
        }
        for(var item in obj){
            if(obj[item] === obj) continue;//存在引用则跳出当前循环
            if(getType(obj[item]) === 'Function'){
                res[item] = new Function("return "+obj[item].toString())();
            }else if(getType(obj[item]) === 'RegExp'){
                res[item] = getReg(obj[item].toString());
            }else if(getType(obj[item]) === 'Object'){
                res[item] = clone(obj[item]);
            }else{
                res[item] = obj[item];
            }
        }
        return res;
    };


В принципе можно реализовать глубокое копирование функций и обычных объектов, а локально делать только простые тесты.Если есть проблемы, пожалуйста, комментируйте и вовремя указывайте.

Конечно, как библиотека функцийlodashиз_.cloneDeep,JQueryиз$.extendБыло достигнуто глубокое копирование, и заинтересованные студенты могут самостоятельно просмотреть исходный код.

использованная литература

developer.Mozilla.org/this-cn/color каждый день...

GitHub.com/Вэн Цзици/блог…