美文网首页
JavaScript关于对象的克隆

JavaScript关于对象的克隆

作者: 黄山淋Slahser | 来源:发表于2017-05-11 23:07 被阅读0次

前言

第一次写简书,简单写一些自己关于自己对前端的理解及实际工作中遇到的问题,如有错误,还请各位指正。

我们都知道js里对象属于引用类型,仅仅是简单的赋值,只是将一个对象在堆中的地址赋给另一个变量,实际指向的还是同一内存空间:

var obj1 = {a: 1,b: 2};
obj2 = obj1;
obj2  // {a: 1,b: 2}
obj2.a = 2;
obj1  // {a: 2,b: 2}

实际上obj1和obj2指向的是相同的对象,所以对obj2进行操作会改变原对象,而在实际应用中,我们常常需要的是克隆一个相同的对象去进行操作。这时我们就会想到使用for(in)去遍历对象进行克隆:

var obj1 = {a: 1,b: 2,c: 3};
var obj2 = {};
for(var key in obj1){
  obj2[key] = obj1[key]
};
obj2 // {a: 1,b: 2,c: 3}

这个时候我们想到去写一个方法实现对象的克隆:

function clone(obj){
    var result={};
    for(key in obj){
        result[key]=obj[key];
    }
    return result;
}
var obj1 = {
        x:1,
        y:2,
        z:{
            a:1,
            b:2,
            c:{
                e:3,
                f:4
            }
        }
    };
var obj2 = clone(obj1)
   console.log(obj2.z.c.f); //4
   obj2.z.c.f = 10;
   console.log(obj1.z.c.f); //10

可以看到我们的克隆并不彻底,对于对象中的对象并没有克隆出来,这时我们需要健壮程序,当我们传入的是一个对象,而如果对象的属性值不单单仅是对象呢?可能是数组,可能是null,或undefined,所以,我们需要对对象及他的属性进行类型检测:

function clone(obj) {
        var result; // 
        if(obj === null){
            return 'null'  //如果是null,直接返回
        }
        else if(obj === undefined){
            return 'undefined'  //如果是undefined,直接返回
        }
        else if(Object.prototype.toString.call(obj).slice(8,-1) === 'Object'){
            result = {}  //这种方式俗称为检查胎记,能直接返回对象的类属性
        }else if(Object.prototype.toString.call(obj).slice(8,-1) === 'Array'){
            result = []
        }else{
            return  obj
        }
        for(var key in obj){
            if(Object.prototype.toString.call(obj[key]).slice(8,-1) ==='Object' || 'Array'){
                result[key] = clone(obj[key]) //递归调用
            }else{
                result[key] = obj[key];
            }
        }
        return result
    }
var obj2 = clone(obj1)
   console.log(obj2.z.c.f); //4
   obj2.z.c.f = 10;
   console.log(obj1.z.c.f); //4

这个时候,我们的方法基本完成,但是,我们有没有想过,如果for(in)循环拿不到对象的属性,那我们怎么办?等等,我们似乎忘记对象的属性还有四大特性了:

var obj = {
        x: 1,
        y: 2
    };
    console.log(Object.getOwnPropertyDescriptor(obj,'x')); 
    // Object {value: 1, writable: true, enumerable: true, configurable: true}
    Object.defineProperty(obj,'x',{
        writable:false,
        enumerable:false,
    }); // 我们重新设置x的特性为不可读写,不可遍历
    obj.x = 2;
    console.log(obj.x);// 1
    var Oobj={};
    for(var key in obj){
        Oobj[key] = obj[key]
    }
    console.log(Oobj); //{y:2},我们压根就拿不到x,更不要说去克隆了

这时我们就需要继续改进我们之前定义的克隆方法了

function clone(obj) {
        var result; 
        if(obj === null){
            return 'null'  //如果是null,直接返回
        }
        else if(obj === undefined){
            return 'undefined'  //如果是undefined,直接返回
        }
        else if(Object.prototype.toString.call(obj).slice(8,-1) === 'Object'){
            result = {}  //这种方式俗称为检查胎记,能直接返回对象的类属性
            var names = Object.getOwnPropertyNames(obj);// 拿到元素所有属性的键值
            for( var i=0 ;i< names.length; i ++){
                var resc = Object.getOwnPropertyDescriptor(obj,names[i]); //拿到属性的特性
                var copy = obj[names[i]]; //元素属性值
                Object.defineProperty(result,names[i],resc);//重新添加属性并设置其特性
                if(Object.prototype.toString.call(copy).slice(8,-1) ==='Object' || 'Array'){
                    result[names[i]] = clone(copy)
                }
            }
        }else if(Object.prototype.toString.call(obj).slice(8,-1) === 'Array'){
            result = [];
            for(var key in obj){
                if(Object.prototype.toString.call(copy).slice(8,-1) ==='Object' || 'Array'){
                    result[key] = clone(obj[key]) //递归调用
                }else{
                    result[key] = obj[key];
                }
            }
        }else{
            return  obj
        }
        return result
    }
    var obj1 = {
        x:1,
        y:2,
        z:{
            a:1,
            b:[1,2,[3,4]],
            c:{
                e:3,
                f:4
            }
        }
    };
    Object.defineProperty(obj1.z,'c',{
        writable:false,
        enumerable:false,
    });
obj2 = clone(obj1);
console.log(obj2); // 与obj1一致 

如有错误或遗漏,欢迎指正,谢谢。

相关文章

  • JavaScript关于对象的克隆

    前言 第一次写简书,简单写一些自己关于自己对前端的理解及实际工作中遇到的问题,如有错误,还请各位指正。 我们都知道...

  • 每日一条JS精华片段:deepClone

    创建对象的深层克隆。克隆基本值,数组和对象 Javascript方法 示例 执行结果 请关注我,每天获得一条精华小片段!

  • 再探原型模式

    再探原型模式 一切都是对象 在JavaScript这门语言中,获取对象的唯一途径就是克隆,而JavaScript中...

  • Javascript 基于原型的面向对象系统编程

    Javascript是使用克隆的原型模式。 1. 原型编程的规则 所有的数据都是对象(javascript中不是所...

  • Javascript中的克隆(拷贝)问题

    克隆(也就是拷贝)是javascript中很重要也很常见的问题。克隆就是将一个对象里的属性、方法等复制到另一个对象...

  • JavaScript浅克隆对象的方法

    Object.assign({}, obj);说明:Object.assign({}, obj)拷贝的是(可枚举)...

  • 简单的JavaScript深度克隆

    相关内容:JavaScript浅克隆对象的方法[https://www.jianshu.com/p/f0eb971...

  • 对象的克隆

    对象的克隆 对象地址的引用: 以上属于对象地址的引用: 一、对象的浅克隆 Person: Demo: 对象浅克隆要...

  • PHP中对象的复制

    潜克隆(浅拷贝) 只能克隆对象的"非对象非资源"数据。但如果对象中属性存储的是对象类型,就可以看到克隆没有克隆对象...

  • JavaScript深拷贝(克隆)特殊对象

    如何克隆一个对象或数组?★☆☆☆☆ 递归深拷贝,参考Lodash的_.closeDeep JSON.parse(J...

网友评论

      本文标题:JavaScript关于对象的克隆

      本文链接:https://www.haomeiwen.com/subject/fmqvtxtx.html