JavaScript初学 学习笔记6:JavaScript之克隆(浅层克隆,深度克隆)

浅层克隆

要将 对象 obj 克隆给对象 obj1

//浅层克隆实现
var obj = {
	name: 'abc',
	age: 20,
	sex: 'male',
	arr: ['aaa', 'bbb', 'ccc']
}

function copy(origin, target) {
	var target = target || {};
	//为了防止用户不传 target(容错),给了参数就直接用,不给就当空对象
	for (var prop in origin) {
		target[prop] = origin[prop];
	}
	return target;
}
var obj1 = copy(obj);

然而,浅层克隆存在相应的问题
在这里插入图片描述

浅层克隆为什么会出现这种问题

首先我们需要清楚 JavaScript 中的数据类型总体来说分为两种,他们分别是:基本数据类型 和 复杂数据类型

基本数据类型(值类型):数值型(Number),字符类型(String),布尔值型(Boolean),null 和 underfined

复杂数据类型(引用数据类型):函数,对象,数组等

  1. 基本数据类型:这些值都有“固定的大小”,往往都保存在"栈内存"中(闭包除外)。变量之间的互相赋值,是指开辟一块新的内存空间,将变量值赋给新变量保存到新开辟的内存里面;之后两个变量的值变动互不影响
  2. 复杂数据类型:引用数据类型的值是保存在堆内存中的对象。变量之间的互相赋值,只是指针的交换,而并非将对象(普通对象,函数对象,数组对象)复制一份给新的变量,对象依然还是只有一个,只是多了一个指引

因此在浅层克隆中

  • 基本数据为值传递,复杂数据类型(对象,数组)仍为引用传递。引用传递使对象指向相同的地址空间,改变一个对象,另一个也会随之改变。

而我们需要的克隆 是所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。

深度克隆思路

需要一个分析环节,分析待拷贝的是什么,是原始值就按原来的方法拷贝过来,是引用值就分析是数组还是对象。如果是数组,就新建一个数组;如果是对象,就新建一个对象。再一层层看,形成一个递归。

思路步骤

  1. 先把所有的值都遍历一遍(看是引用值和原始值)
  2. 判断是原始值,还是引用值?用 typeof 判断是不是 object。
    1. 如果是原始值就直接拷贝。
    2. 如果是引用值,判断是数组还是对象。
  3. 判断是数组还是对象
    1. 如果是数组,就新建一个空数组。
    2. 如果是对象,就新建一个空对象。
  4. 建立了数组以后,如果是挨个看原始对象里面是什么,都是原始值就可以直接copy过来了;或者,建立了对象以后,挨个判断对象里面的每一个值,看是原始值还是引用值
  5. 递归

知识点补充——如何区分 数组 和 对象

1.instanceof

在这里插入图片描述
可通过 instanceof Array 来判断是否是数组

2.constructor

在这里插入图片描述

同样,也可通过construct 判断其构造函数来区分 数组 和 对象

3.toString

在这里插入图片描述
这里,我们使用

Object.prototype.toString.call(a)

来实现区分(不是用.toString() )

深度克隆代码实现

var obj = {
	name: 'abc',
	age: 20,
	sex: 'male',
	arr: ['aaa', 'bbb', 'ccc', {
		qq: 12345,
		email: '12345@qq.com'
	}]
}

function deepCopy(origin, target) {
	var target = target || {};
	// 为了防止用户不传 target(容错),给了参数就直接用,不给就当空对象
	toStr = Object.prototype.toString;
	// 给函数创建一个引用 简化代码
	var arrStr = '[object Array]';
	// 给该比对字符串创建一个引用 简化代码

	// var objStr = '[object Object]';

	for (var prop in origin) {
		// 先判断是不是原型上的属性,如果是false 就是原型上的属性,而我们不需要拷贝原型上的属性
		if (origin.hasOwnProperty(prop)) {
			if (typeof (origin[prop]) !== 'null' && typeof (origin[prop]) == 'object') {
				// 判断是 引用值 再区分数组和对象
				if (toStr.call(origin[prop]) == arrStr) {
					// 是数组 创建空数组
					target[prop] = [];
				} else {
					// 是对象 创建空对象
					target[prop] = {};
				}
				deepCopy(origin[prop], target[prop]);
			} else {
				// 判断是 原始值 直接进行赋值
				target[prop] = origin[prop];
			}
		}
	}
	return target;
}

var obj1 = deepCopy(obj);

更改前
在这里插入图片描述
更改后的obj的arr属性并未被更改
在这里插入图片描述


end

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值