前言:
栈堆、基本数据类型、引用数据类型
栈堆:存放数据的地方
基本数据类型:number,string,boolean,null,undefined.
引用数据类型(Object类)有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等。
浅拷贝概念:
如果是数组,我们可以利用数组的一些方法,比如slice,concat方法返回一个新数组的特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用concat方法克隆并不完整,如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或数组,就只会拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化,我们把这种复制引用的拷贝方式称为浅拷贝。
实现方式:
var shallowCopy function(obj){
//只拷贝对象
if(typeof obj !== 'object') return;
//根据obj的类型判断是新建一个数组或对象
var newObj = obj instanceof Array ? []:{};
//遍历obj,并且判断是obj的属性才拷贝
for(var key in obj){
if(obj.hasOwnProperty(key)){
newObj[key] = obj[key];
}
}
return newObj;
}
深拷贝概念:
深拷贝是指完全拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,不会影响到另一个。
实现方式:
方法1:适用于对象和数组
JSON对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以吧JSON字符串反序列化为一个js对象,通过这两种方法,可以实现对象的深复制,但是这个方法不能拷贝函数。
function deepClone(obj){
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
let a=[0,1,[2,3],4],
b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
方法2:递归调用
var deepCopy = function(obj){
if(typeof obj != 'object') return;
var newObj = obj instanceof Array ? []:{};
for(var key in obj){
if(obj.hasOwnProperty(key)){
newObj[key] = typeof obj[key] == 'object' ?deepCopy(obj[key]):obj[key];
}
}
return newObj;
}
方法3:JQ的extend方法
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。
let a=[0,1,[2,3],4],
b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
通过递归可以实现对象的深度克隆,但是不论ES5或ES6实现,都有同样的缺陷,就是只能实现特定的object的深度复制(比如数组和函数),不能实现包装对象Number,String,Boolean,以及Date对象,RegExp对象的复制。
valueof()函数
所有的对象都有valueOf方法,valueOf方法对于:如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。数组、函数和正则表达式简单地继承了这个默认方法,调用这些类型的实例的valueOf()方法只是简单返回这个对象本身。
对于原始值或包装类(Number、String、Boolean):
function baseClone(base){
return base.valueOf();
}
//Number
var num = new Number(1);
var newNum = baseClone(num);
对于Date类型:
因为valueOf()方法,日期类定义的valueOf()方法会返回它的一个内部表示:1970年1月1日以来的毫秒数,因此我们可以在Date的原型上克隆定义的方法:
Date.prototype.clone = function(){
return new Date(this.valueOf());
}
var date = new Date('2010');
var newDate = date.clone();
//newDate-> Fri Jan 2010 08:00:00 GMT+0800
对于正则对象RegExp:
RegExp.prototype.clone = function(){
var pattern = this.valueOf();
var flags ='';
flags += pattern.global ?'g':'';
flags += pattern.ignoreCase ? 'i':'';
flags += pattern.multiline ?'m':'';
return new RegExp(pattern.source,flags);
}
//var reg = new RegExp('/111/');
var newReg = reg.clone();