浅克隆
概念:只复制对象的第一级属性值。如果对象的第一级属性中又包含引用类型,则只复制地址。
问题:如果对象中又包含引用类型的属性值,则导致克隆后,新旧对象依然共用同一个引用类型的对象属性值。
结果:任意一方修改了引用类型的对象内容,都会导致另一方同时受影响。如下代码
(一):Object.assign()
var obj = {a:1,b:2,c:{d:10,e:20}}
var obj1 = {}
Object.assign(obj1,obj) //克隆
obj.a = 2;
obj.c.d = 100
console.log(obj) // {a:2,b:2,c:{d:100,e:20}}
console.log(obj1) // {a:1,b:2,c:{d:100,e:20}}
(二):展开运算符(...)
var obj = {a: 1,b: 2,c: {d: 10,e: 20}}
var obj1 = {}
obj1 = {...obj} //克隆
obj.a = 2;
obj.c.d = 100
console.log(obj) // {a:2,b:2,c:{d:100,e:20}}
console.log(obj1) // {a:1,b:2,c:{d:100,e:20}}
(三):函数库lodash的_.clone方法
var obj = {a: 1,b: 2,c: {d: 10,e: 20}}
var obj1 = {}
obj1 = _.clone(obj) //克隆
obj.a = 2;
obj.c.d = 100
console.log(obj) // {a:2,b:2,c:{d:100,e:20}}
console.log(obj1) // {a:1,b:2,c:{d:100,e:20}}
深克隆
概念:不但复制对象的第一级属性值,而且,即使对象中又包含引用类型的属性值,深克隆也会继续复制内嵌类型的属性值。
结果: 克隆后,两个对象彻底再无关。
(一):JSON.parse(JSON.stringify())
var obj = {a:1,b:2,c:{d:10,e:20}}
var obj1 = {}
obj1=JSON.parse(JSON.stringify (obj)) //克隆
obj.a = 2;
obj.c.d = 100
console.log(obj) // {a:2,b:2,c:{d:100,e:20}}
console.log(obj1) // {a:1,b:2,c:{d:10,e:20}}
弊端:以下两种情况无法实现深拷贝
- 在
obj对象种加入set get方法,会导致方法被运算 - 对
obj对象通过Object.defineProperty()添加属性时无法被拷贝
Object.defineProperty(obj,"h",{
value :30
})
(二):递归调用
复习一下递归:程序调用自身的编程技巧称为递归(recursion)。
function factorial(n) {
if (n == 1) return n;
return n * factorial(n - 1)
}
console.log(factorial(5)) // 5 * 4 * 3 * 2 * 1 = 120
构成递归需具备边界条件、递归前进段和递归返回段,当边界条件不满足时,递归前进,当边界条件满足时,递归返回。阶乘中的n == 1就是边界条件。
方法一
function deepClone(target) {
let newObj; // 定义一个变量,准备接新副本对象
// 如果当前需要深拷贝的是一个引用类型对象
if (typeof target === 'object') {
if (Array.isArray(target)) { // 如果是一个数组
newObj = []; // 将newObj赋值为一个数组,并遍历
for (let i in target) { // 递归克隆数组中的每一项
newObj.push(deepClone(target[i]))
}
// 判断如果当前的值是null;直接赋值为null
} else if (target === null) {
newObj = null;
// 判断如果当前的值是一个正则表达式对象,直接赋值
} else if (target.constructor === RegExp) {
newObj = target;
} else {
// 否则是普通对象,直接for in循环递归遍历复制对象中每个属性值
newObj = {};
for (let i in target) {
newObj[i] = deepClone(target[i]);
}
}
// 如果不是对象而是原始数据类型,那么直接赋值
} else {
newObj = target;
}
// 返回最终结果
return newObj;
}
//调用
var arr= [1,2,3,{name:'zs',age:14}]
var arr1=deepClone(arr) //克隆
arr[1]=10;
arr[3].name='lisi'
console.log(arr) // [10,2,3,{name:'lisi',age:14}]
console.log(arr1) // [1,2,3,{name:'zs',age:14}]
方法二
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;
}
解析(一): typeof
我之前一直以为如果target为数组,则 输出Array; 其实输出的是 Object;因为Array 也是特殊的Object;
typeof "John" // 返回 string
typeof 3.14 // 返回 number
typeof false // 返回 boolean
typeof [1,2,3,4] // 返回 object
typeof {name:'John'} // 返回 object
typeof undefined // undefined
typeof null // object
null === undefined // false
null == undefined // true
解析(二):.constructor
概念:属性返回对创建此对象的数组函数的引用。
不懂的可以参照:www.lccee.com/web/jsref/j…
解析(三):instanceof
概念:instanceof运算符测试构造函数的属性是否 出现prototype在对象的原型链中的任何位置。返回值是一个布尔值。
不懂的可以参照:developer.mozilla.org/en-US/docs/…
解析(四):hasOwnProperty
概念:hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)