javascript. Клонирование объектов

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

var Copier = {   
    copy: function (object) {       
        var newObject;   
       
        // for copying arrays
        if (object.constructor === Array) {
            newObject = [];
            for (var i = 0, item, size = object.length; i < size; i++) {
                if (object[i].constructor === Array || object[i].constructor === Object) {
                    item = this.copy(object[i]);
                }
                else {
                    item = object[i];
                }
                newObject = newObject.concat(item);
            }           
        }
        // for copying objects
        else if (object.constructor === Object) {
            newObject = {};           
            for (var property in object) {
                if (object.hasOwnProperty(property)) {
                    if (object[property].constructor === Array || object[property].constructor === Object) {
                        newObject[property] = this.copy(object[property]);
                    }
                    else {
                        newObject[property] = object[property];
                    }
                }
            }           
        }
        // for copying other elements
        else {       
            newObject = object;
        }
       
        return newObject;       
    }   
};


Данный объект Copier имеет только один метод copy, собственно который и делает всю основную работу по клонированию. На входе могут быть объекты разного типа: и массивы, и чистые объекты, и массивы, содержащие ссылки на объекты, и простые элементы, что возможно за счет глубинного рекурсивного просмотра.Стоит отметить, то в данном решении для проверки типов также можно воспользоваться следующим способом:

// if object is Object
Object.prototype.toString.call(object) === '[object Object]'

// if object is Array
Object.prototype.toString.call(object) === '[object Array]' 

Если не ошибаюсь, то такого рода проверки более предпочтительны по сравнению с такими как:

// if object is Object
object.constructor === Object
object instanceof Object

// if object is Array
object.constructor === Array
object instanceof Array

И связано это как Вы уже догадываетесь с различиями на уровне браузеров. В этом случае наше решение можно представить в следующем виде:

var Copier = {  
    copy: function (object) {      
        var newObject;  
      
        // for copying arrays
        if (this.isArray(object)) {
            newObject = [];
            for (var i = 0, item, size = object.length; i < size; i++) {
                if (this.isArray(object[i]) || this.isObject(object[i])) {
                    item = this.copy(object[i]);
                }
                else {
                    item = object[i];
                }
                newObject = newObject.concat(item);
            }          
        }
        // for copying objects
        else if (this.isObject(object)) {
            newObject = {};          
            for (var property in object) {
                if (object.hasOwnProperty(property)) {
                    if (this.isArray(object[i]) || this.isObject(object[i])) {
                        newObject[property] = this.copy(object[property]);
                    }
                    else {
                        newObject[property] = object[property];
                    }
                }
            }          
        }
        // for copying other elements
        else {      
            newObject = object;
        }
      
        return newObject;      
    },
    isArray: function (object) {
        return Object.prototype.toString.call(object) === '[object Array]';
    },
    isObject: function (object) {
        return Object.prototype.toString.call(object) === '[object Object]';
    }
};


Стоит сделать небольшое замечание по поводу массивов. Так как массивы - это также объекты, то проверка типа array instanceof Object будет успешной. Нужно быть бдительным. Вообще таким образом можно проверять и все остальные типы - Function, String, Number и прочее. Всем успехов :)