js实现浅拷贝和深拷贝

浅拷贝

在进行拷贝对象的时候,如果属性是对象或者数组,则传递的是引用地址;若对这样的属性进行修改,那么父子对象之间就会发生关联。

1)‘=’赋值,将对象的引用赋值

var a={
    
    key1:"11111"}
function Copy(p){
    
    
   var c ={
    
    };
   for (var i in p){
    
    
      c[i]=p[i]
   }    
   return c;
}

a.key2 = ["小辉","小辉"]
var b = Copy(a);
b.key3 = "33333"

alert(b.key1)//11111
alert(b.key3)//33333
alert(a.key3);//undefined

b.key2.push("大辉")
alert(a.key2);//小辉,小辉,大辉

2)Object.assign(),是ES6的新函数

函数结构:Object.assign(target, ...sources)

参数:
target:目标对象
sources:任意多个源对象
返回值:返回目标对象
var obj = {
    
     a: {
    
    a: "hello", b: 21} };
var initalObj = Object.assign({
    
    }, obj);

initalObj.a.a = "changed";
console.log(obj.a.a); // changed

initalObj.b = 18;
console.log(obj.b); // undefined

深拷贝

实现复制的对象是另一个独立的对象,而不是原对象的引用。

1)直接复制,属性类型属于值类型

var obj1 = {
    
     a: 10, b: 20, c: 30 };
var obj2 = {
    
     a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);// { a: 10, b: 20, c: 30 } 
console.log(obj2);// { a: 10, b: 100, c: 30 }

2)JSON.stringify 把对象转成字符串,再 JSON.parse 把字符串转成新的对象

var obj1 = {
    
     body: {
    
     a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);// { body: { a: 10 } }
console.log(obj2);// { body: { a: 20 } }
console.log(obj1 === obj2);// false
console.log(obj1.body === obj2.body);// false

只适用于可以转换成JSON格式的对象,像function、RegExp不可以使用此方法。

常用: Number,String,Boolean,Array,扁平对象

var obj1 = {
    
     fun: function(){
    
     console.log(123) } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun);// 'function'
console.log(typeof obj2.fun);// 'undefined' <-- 没复制

3)递归,把父对象中所有属于对象的属性类型都遍历赋给子对象

function deepClone(initalObj, finalObj) {
    
    
  var obj = finalObj || {
    
    };
  for (var i in initalObj) {
    
     // for in循环适用于对象、数组的遍历
    var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) continue;
    if (typeof prop === 'object') {
    
    
      obj[i] = (prop.constructor === Array) ? [] : {
    
    };  // 判断是对象还是数组
      arguments.callee(prop, obj[i]);  // 相当于 deepClone(prop,obj[i]); 降低耦合性
    } else {
    
    
      obj[i] = prop;
    }
  }
  return obj;
}

var obj1 = {
    
    };
var obj2 = {
    
     a: {
    
    a: "hello", b: 21} };
deepClone(obj2, obj1);
console.log(obj1.a); // Object { a: "hello", b: 21 }

【补充1】

JS中的||运算:

扫描二维码关注公众号,回复: 12725368 查看本文章
  • 只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。
  • 只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。

JS中的&&运算:

  • 只要“&&”前面是false,无论“&&”后面是true还是false,结果都将返“&&”前面的值;
  • 只要“&&”前面是true,无论“&&”后面是true还是false,结果都将返“&&”后面的值;

【补充2】

在函数内部,有两个特殊的对象:argumentsthis

其中, arguments 的主要用途是保存函数参数,有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。

arguments.callee()常用于递归,指向本函数。

4)Object.create()方法

function deepClone(initalObj, finalObj) {
    
    
  var obj = finalObj || {
    
    };
  for (var i in initalObj) {
    
     // for in循环适用于对象、数组的遍历
    var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) continue;
    if (typeof prop === 'object') {
    
    
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
    
    
      obj[i] = prop;
    }
  }
  return obj;
}

var obj1 = {
    
    };
var obj2 = {
    
     a: {
    
    a: "hello", b: 21} };
deepClone(obj2, obj1);
console.log(obj1.a); // Object { a: "hello", b: 21 }

直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

5)jquery 提供的$.extend

var $ = require('jquery');
var obj1 = {
    
    
  a: 1,
  b: {
    
     f: {
    
     g: 1 } },
  c: [1, 2, 3]
};

var obj2 = $.extend(true, {
    
    }, obj1);
console.log(obj1.b.f === obj2.b.f);// false

6)slice和concat对数组的深拷贝和浅拷贝

  • 浅拷贝:
var arr1 = ["red","yellow","black"];
var arr2 = arr1;
arr2[1] = "green";
console.log("数组的原始值:" + arr1 ); // 数组的原始值:red,green,black
console.log("数组的新值:" + arr2); // 数组的新值:red,green,black
  • 深拷贝:(仅适用于对不包含引用对象的一维数组的深拷贝)
// 方法一:slice(),数组截取,并返回一个新的数组
var arr1 = ["1","2","3"];
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log("数组的原始值:" + arr1 ); // 数组的原始值:1,2,3 
console.log("数组的新值:" + arr2 ); // 数组的新值:1,9,3

// 方法二:concat(),合并数组,并返回一个新的数组
var arr1 = ["1","2","3"];
var arr2 = arr1.concat(); // concat()括号内,可以添加数组,或者数组元素作为参数
arr2[1] = "9";
console.log("数组的原始值:" + arr1 ); // 数组的原始值:1,2,3 
console.log("数组的新值:" + arr2 ); // 数组的新值:1,9,3

猜你喜欢

转载自blog.csdn.net/weixin_43973415/article/details/113412353