arr.concat(): 数组浅拷贝
let arr1 = [3,4,5,6,{user:'huang'}]
let arr2 = arr1.concat()
arr2[0] = 110
arr2[4].user = 'liu'
console.log(arr1) // [3,4,5,6, {user: "liu"}] // 里面的对象跟着改变了
console.log(arr2) // [110,4,5,6, {user: "liu"}
arr.slice(): 数组浅拷贝
let arr1 = [3,4,5,6,{user:'huang'}]
let arr2 = arr1.slice()
arr2[0] = 110
arr2[4].user = 'liu'
console.log(arr1) // [3,4,5,6, {user: "liu"}]
console.log(arr2) // [110,4,5,6, {user: "liu"}]
使用HTML5的JSON方法:parse()和stringify()方法实现浅克隆和深度克隆
这个方法如果需要做到兼容性比较好的话需要借助josn官网下的json2.js这个插件来兼容HTML5的JSON方法(parse()和stringify()方法),直接将这个插件引入即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var a = {
name : { age : 100 },
num: [2,3,4]
};
var str = JSON.stringify(a); //将a对象解析成字符串
var b = JSON.parse(str); //将str字符串解析成对象并且赋值给b,那么b这个对象就跟a对象没有引用关系
b.name.age = 200;
b.num = [5,6,7];
alert( a.name.age ); //100
alert( b.name.age ); //200
alert( a.num ); //2,3,4
alert( b.num ); //5,6,7
</script>
</body>
</html>
这种方式拷贝的数据里不能有函数,因为不能处理函数数据,如果拷贝的数据里有函数,拷贝完的结果这个函数变成了null,因为JSON.stringify()这个方法里只能是原生js的obj或者数组
let arr1 = [3,4,5,6, function fun() {}]
let arr2 = JSON.parse(JSON.stringify(arr1))
console.log(arr1) // [3, 4, 5, 6, ƒ] f就是最后一个元素
console.log(arr2) //[3, 4, 5, 6, null]
需求:不借助josn官网下的json2.js这个插件实现一个既可以浅克隆又可以深度克隆的一个方法,同时兼容性要好
原理:首先使用window.JOSN来判断浏览器支不支持HTML5中的JOSN的方法,如果支持则使用JOSN的方法,如果不支持那么使用原生js实现深度克隆的方法(使用的递归算法)
特点:拷贝的时候生成新的数据,修改拷贝以后的数据不会影响原数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var cloneObj = function (obj) {
var str, newobj = obj.constructor === Array ? [] : {};
if (typeof obj !== 'object') { // 数组的typeof也是object
return;
} else if (window.JSON) {
str = JSON.stringify(obj), //序列化对象
newobj = JSON.parse(str); //还原
} else {
for (var i in obj) { //如果obj是null,那么这里是不会遍历的,因为null的typeof也是object,for in遍历对象的时候 i是对象的key,数组的时候i是下标
newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};
//测试
var student = {
name: "yxz",
age: 25,
sex: "male",
cn: {city: "shenz"}
};
//执行深度克隆,对象里面有函数不行,不包含函数
var newStudent = cloneObj(student);
delete newStudent.sex;
console.log(newStudent);
console.log(student);
</script>
</body>
</html>
测试结果:
下面代码也是可以包含函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var cloneObj = function (obj) {
var str, newobj = obj.constructor === Array ? [] : {};
if (typeof obj !== 'object') { // 数组的typeof也是object
return obj;
} else if (window.JSON) {
str = JSON.stringify(obj), //序列化对象
newobj = JSON.parse(str); //还原
}
for (var i in obj) {
newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
}
return newobj;
};
//测试
var student = {
name: "yxz",
age: 25,
sex: "male",
cn: {city: "shenz"},
fn1: function (n) {
return n + 2
}
};
//执行深度克隆
var newStudent = cloneObj(student);
delete newStudent.sex;
console.log(newStudent);
console.log(student);
</script>
</body>
</html>
判断数据类型的另外一种方式——Object.prototype.toString
let arr = [2, 3, 4, 5, {user:'huang'}]
let obj = {user:'huang', age: 33}
// 通过原型方法:Object.prototype.toString,没有被修改过,最原始的方法
// 利用call的特点让我们指定的数据去调用这个原型方法
let dataType1 = Object.prototype.toString.call(arr)
let dataType2 = Object.prototype.toString.call(obj)
console.log(dataType1) // 打印结果:[object Array],数据类型是string,所以可以进行字符串切割
console.log(dataType2) // 打印结果:[object Object],数据类型是string,所以可以进行字符串切割
let dataType3 = dataType1.slice(8, -1) // slice包含开始位置,不包含结束位置,可以倒着数,-1就是最后一位,这个不包含结束位置
let dataType4 = dataType2.slice(8, -1) // slice包含开始位置,不包含结束位置,可以倒着数,-1就是最后一位,这个不包含结束位置
console.log(dataType3) //Array
console.log(dataType4) //Object
深度拷贝具体实现代码
// 检测数据类型的功能
function checkType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
// 实现深度拷贝(数组/对象)
function clone(target) {
// 判断要拷贝的数据的数据类型
// 初始化变量result,成为最终拷贝的数据
let result, targetType = checkType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
for (let i in target) {
// 获取遍历数据结构的每一项值
let value = target[i]
if (checkType(value) === 'Object' || checkType(value) === 'Array') { // 判断每一项值是否是对象/数组,如果是继续遍历
clone(value)
} else {
result[i] = value
}
}
return result
}
//测试
var student = {
name: "yxz",
age: 25,
sex: "male",
cn: {city: "shenz"}
};
//执行深度克隆,对象里面有方法也是可以的
var newStudent = clone(student);
delete newStudent.sex;
console.log(newStudent);
console.log(student);