JavaScript - 克隆

本文探讨了JavaScript中对象的克隆方法,包括浅拷贝和深拷贝的区别。介绍了直接赋值、展开运算符、Object.assign等浅拷贝方式的局限性,以及JSON.parse(JSON.stringify())和自定义深度克隆函数实现深拷贝的详细过程。
摘要由CSDN通过智能技术生成
  • 把下面obj对象克隆到一个新的对象obj1中
let obj = {
    name: '车车',
    age: 18,
    skill: ['js', 'vue'],
    family: {
        sister: 'cgz',
        parent: {
            mather: 'wyp',
            father: 'cyx'
        }
    },
    say: function () {
        console.log('hello!!')
    },
    b:undefined,
}

1.直接赋值

let obj1 = obj
obj1.family.sister = 'kkk'  // obj也变了
console.log(obj)            // 原来的对象obj.family.sister = 'kkk' 

2.展开运算符

let obj1 = {...obj}

3.Object.assign

let obj1 = {}
console.log(Object.assign(obj1,obj))
obj1.skill[0] = 'css' //依旧改变了原来的对象obj
console.log(obj)      //obj.skill[0] = 'css' 

以上三种方法:直接赋值、展开运算符、Object.assign实现的克隆是浅度克隆;即:只能拷贝原始类型,对于引用值,拷贝的是地址,对象的引用,而不是对象本身,一旦内容改变,指向这个内容的地址中的内容都会变。

  • 深度克隆:
    1 . JSON.parse(JSON.stringify())
    用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象。
let obj1 = JSON.parse(JSON.stringify(obj))
obj1.skill[1] = 'webpack'  //obj不会被改变
console.log(obj1)
// 但是无法克隆函数和 undefined
  1. 自己实现一个深度克隆方法:
  • 分析:
  1. 它要达到的目的是,不管是克隆的原始值还是引用值,当改变时另一个不会发生变化;我们根据浅度克隆可以知道,克隆原始值是直接拷贝,一个的改变不会影响另一个,但是引用值它拷贝的是地址,所以当一个改变会影响另一个跟他一起改变
  2. 首先遍历对象,看它的属性是原始值还是引用值,如果是原始值,则直接拷贝,如果是引用值,则需要判断是对象还是数组,做出辨别后建立相应的[]/{},然后拷贝[]/{}时,又需要判断里面的值是原始值还是引用值,如果是引用值,如刚才的方法进行循环判断辨别
  • 过程:
    1. 遍历对象 obj for …in
    2. 判断是不是原始值 typeof() --> object
    3. 如果是引用值,判断是数组还是对象
    (1) . instanceof a的原型链上有没有b的原型
    (2) . toString 建议用
    (3) . constructor
    4. 建立相应的数组或对象
    5. 递归
function deepClone(origin,target){
	var target=target||{};  
	    toStr=Object.prototype.toString,  //用toString方法区分对象和数组
	    arrStr="[object Arrary]";        //[]
	for(var prop in origin){   
		if(origin.hasOwnProperty(prop)){
		//只克隆自己的 排除原型链上的属性
			if(origin[prop] !=="null" &&  typeof(origin[prop])=='object'){   
			//引用值
			//  if(toStr.call(origin[prop])==arrStr){      
                   //数组
			//	    target[prop]=[]; 
			//	}else{   
			       //对象                            
			//		target[prop]={};
			//	}
				target[prop]=toStr.call(origin[prop])==arrStr ? [] : {};
				deepClone(origin[prop],target[prop]);
				//属性里边的属性值是原始值还是引用值?进行相同的判断  调用自身实现相同功能  递归 
			}else{    
			    //原始值                                                                           
				target[prop]=origin[prop];  //直接拷贝
			}
		}
	}
	return target;  
}
deepClone(obj,obj1);

补充:数据类型判断 :

  1. typeof :如下,可以发现对于引用值和null,无法判断出真正的类型
typeof "a"                //"string"
typeof 1                  //"number"
typeof false              //"boolean"
typeof undefined          //"undefined"
typeof null               //"object"
typeof []                 //"object"
typeof {}                 //"object"
typeof function(){}       //"function"
  1. A instanceof B : 判断A对象是不是B 构造函数构造出来的 返回true / false
function Person() {}
var person= new Person();
person instanceof Person  //true
//注意看下面例子
person instanceof Object  //true

[] instanceof Object  //true
[] instanceof Array   //true
function Person() {}
var person= new Person();
var obj={};

obj instanceof Person     //false
person instanceof Array  //false

所以:理解instanceof时应该这样理解:
A instanceof B : 看A对象的原型链上 有没有 B 的原型

  1. constructor :返回构造自己的构造函数
[].constructor    //ƒ Array() { [native code] }

let obj = {}
obj.constructor  //ƒ Object() { [native code] }
  1. Object.prototype.toString.call() :tostring方法会返回调用他的构造函数 ‘[object 构造函数]’
let toString = Object.prototype.toString;

toString.call(new String); // [object String]
toString.call(new Number) // [object Number]
toString.call(true) // [object Boolean]
toString.call(null); // [object Null]
toString.call(undefined); // [object Undefined]
toString.call(Symbol()) // [object Symbol]

toString.call([]); // [Object Array]
toString.call({}) // [object Object]
toString.call(function(){}) // [object Function]

toString.call(new Date); // [object Date]
toString.call(new RegExp) // [object RegExp]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值