2020.11.6
由于之前在第一遍学习 Javascript 的过程中对知识点理解的不是很透彻,对浅层克隆和深层克隆的理解比较模糊,今天在复习面向对象的时候醍醐灌顶,于是乎记录一下自己的理解。
一、首先关于原始值和引用值
1、数据类型分为:
(1)不可改变的原始值:number, string, boolean, undefined, null(栈内存中)
(2)引用值:array, object, function, RegExp,Data(引用数据类型保存在堆内存中,二而栈中存放的仅仅是一个地址)
2、他们之间的区别
(1)存储方式不同
- 原始值存储在栈中。意思就是说,当一个原始变量把值赋给另一个原始变量时,只是把栈中的内容复制给另一个原始变量,此时这两个变量互不影响,即当一个变量值改变时,另一个变量不会因此而发生任何变化。
- 引用值把引用变量存储在栈中,而实际的对象存储在堆中。每一个引用变量都有一根指针指向其堆中的实际对象。
(2)引用值有属性和方法,原始值没有(但是!包装类可以让原始值拥有属性和方法,这个过程是隐式的,例如 string.length是可以查看的)
二、原始值和引用值的比较和赋值
1、原始值之间的比较时,值相等即相等。
2、引用值之间的比较时,引用值的值和地址都相等才相等。
而在赋值的时候,原始值只是把具体值赋给另一个变量,两个变量之间还是独立的,引用值不一样,引用值的值和地址都进行赋值。因此会导致修改一个引用值变量时会影响到被他赋值的另一个引用值,所以,这才有了克隆。
var obj = {
name: "Tony",
}
obj2 = obj;
obj2.name = "Marry";
console.log(obj.name);
//结果是打印出Marry
//把引用值obj赋值给了obj2,是把obj的值和地址都赋值给了obj2
//所以在后续改变obj2的属性时,obj的属性也会变化,
//这样使得两个对象不相互独立,很不好
//所以进行克隆
三、浅层克隆
浅层克隆只能对只有原始值属性的对象进行复制之后不相互影响,具体是使用for in 循环。
var obj = {
name: "Tony",
age: 20
}
function clone(origin, target){
var target = target || {};
//上面这一句是容错,也就是可以不传第二个参数
//直接用变量接收返回值。
for(var prop in origin){
target[prop] = origin[prop];
}
return target;
}
var obj2 = {}
clone(obj, obj2);
// var obj2 = clone(obj);
obj2.name = "Marry";
console.log(obj.name);
//这下修改obj2,不会影响到obj
四、深层克隆
浅层克隆复制不了有引用值的对象,是不完美的,因此还需要再浅层克隆内部先判断属性是原始值还是返回值,再进一步去实现复制,具体方法是用递归。
- 顺便复习一下递归:记住两个点,(1)找规律;(2)找出口。
思考过程:
- 先判断是不是原始值
- 判断是数组还是对象
- 建立相应的数组或对象(循环)
实现过程:
- 遍历对象 for in 循环
- 判断原始值 typeof()
- 判断数组或对象(四种方法)
- 建立数组/对象
- 实现递归
var Obj1 ={
name:"Tom",
age:30,
work: function(){
console.log("a");
},
college:['john','marry'],
border:{
name:'kiki',
age:'19',
friend:['koko','mimi']
}
}
function deepClone(origin, target){
var target = target || {};
var toStr = Object.prototype.toString;
var arrStr = '[object Array]';
for(var prop in origin){
//每一个for in 循环都要判断一次hasOwnProperty
//防止访问到原型上的属性
if(origin.hasOwnProperty(prop)){
if(origin[prop] != "null"
&& typeof(origin[prop])== 'object'){
if(toStr.call(origin[prop]) == arrStr){
target[prop] = [];
}else{
target[prop] = {};
}
deepClone(origin[prop], target[prop]);
//递归
}else{
target[prop] = origin[prop];
}
}
}
return target;
}
var Obj2 = deepClone(Obj1);
console.log(Obj2);
Obj2.name = "Marry";