「回顾2022,展望2023,我正在参与2022年终总结征文大赛活动」

前言

JavaScript语言中,你是否分的清什么时候是深仿制,什么时候是浅仿制呢?究竟咱们仿制完一个方针后,怎样的仿制会导致新方针引起原方针改动,怎样的仿制不会导致原方针随新方针改动呢?下面我就来介绍一下深浅仿制吧。

浅仿制的界说

望文生义,浅仿制仿制出来的原方针里边的值会随着新方针改动而改动,也便是说浅仿制是将引证地址仿制给一个新的方针,所以当引证地址对应的值发生改变时,原方针和新方针都会改动。简而言之便是两个方针共用一个引证地址

深仿制的界说

当咱们知道了浅仿制的界说后,那深仿制既是仿制出两个如出一辙的两个方针,并且这两个方针更改自己的值不会影响另外一个方针里边的值,也便是说深仿制的两个方针不共用一个引证地址。

完成深or浅仿制的办法

浅仿制

1、赋值

let a = {
   age: 1
 }
 let b = a
 a.age = 2
 console.log(b.age); // 2
 b.age = 3
 console.log(a.age); // 3

赋值便是一个很典型的浅仿制,由于两个方针运用的是同一个引证地址,所以当值改动时,两个方针都会改动。

2. Object.assign()

let a = {
  like:{
    n1:'reading',
    n2:'runding'
  }
}
let b = Object.assign({},a)
a.like = { //深仿制   {like: { n1: 'reading', n2: 'runding' } }
  n3:'coding' 
}
a.like.n1 = 'coding' //浅仿制  {like: { n1: 'coding', n2: 'runding' } }
console.log(b);

当咱们运用Object.assign()仿制一个方针后,原方针第一层值改变时,新方针的值不会改动,为深仿制。原方针非第一层值改变时,新方针的值会改动,为浅仿制。

3. 解构

let a = {
  age: 1,
  like: {
    n1: 'reading',
    n2: 'runding'
  }
}
let b = { ...a }
a.age = 2 //深仿制
a.like.n1 = 'coding'  //浅仿制
console.log(b);

解构办法与Object.assign()十分类似,能够参照Object.assign()的解释

深仿制

1. JSON.parse() 和 JSON.stringify()

let a = {
  age: 1
}
let c = JSON.parse(JSON.stringify(a))
a.age = 3
console.log(c.age); // 1

当咱们运用JSON.parse()JSON.stringify() 和对c赋值时,当原方针改动时,新方针不会随之改动。

留意

let obj = {
  a:1,
  b:{
    c:2,
    d:3
  },
  e:undefined,
  f:Symbol('hello'),
  g:function(){}
}
let newobj = JSON.parse(JSON.stringify(obj))
console.log(newobj); //{ a: 1, b: { c: 2, d: 3 } }

还有一点要留意的便是JSON.parse() 和 JSON.stringify()不能仿制undefined、Symbol类型、函数。

可深可浅办法

let arr = ['old', 1, true, null, undefined]
let newArr = arr.concat() //深仿制
let newArr1 = arr.slice() //深仿制
arr[0] = 'new'
console.log(newArr); // [ 'old', 1, true, null, undefined ]
console.log(newArr1); // [ 'old', 1, true, null, undefined ]
let arr = [{old:'old'},['old']]
let newArr = arr.concat() //浅仿制
let newArr1 = arr.slice() //浅仿制
arr[0].old = 'new' 
arr[1][0] = 'new'
console.log(newArr);
console.log(newArr1);

当arr为原始类型时,即为深仿制,为引证类型时,即为浅仿制。(和Object.assign()的原理很类似。)

手写深or浅仿制的办法

浅仿制

function shallowCopy(obj) {
  if(typeof obj !== 'object') return
  var newObj = obj instanceof Array ? [] : {}
  for(let i in obj){
  if(obj.hasOwnProperty(i)){
    newObj[i] = obj[i]
  }
  }
  return newObj
}
let a =[{c:1},2,3,[2]]
let b = shallowCopy(a)
a[0].c = 222
console.log(b); // [ { c: 222 }, 2, 3, [ 2 ] ]

这里有一点咱们要留意的便是,在浅仿制的办法里,原始类型仍是为深仿制。

深仿制

function deepCopy(obj) {
  if (typeof obj !== 'object') return  //递归完毕条件
  let newObj = Array.isArray(obj) ? [] : {}; // 判断类型
  for (let i in obj) {
    if(obj.hasOwnProperty(i)){
      newObj[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i] // 递归办法,进行仿制
    }
  }
  return newObj;
}
let a =[{c:1},2,3,[2]]
let b = deepCopy(a)
a[0].c = 222
console.log(b);

深仿制即时一层一层递归进行仿制仿制,完成了不会随原始值改变而改变的深仿制。

jQuery的extend办法

1. 介绍

jQuery.extend() 函数用于 将一个或多个方针的内容兼并到方针方针。这一点与Object.assign()办法类似。

但extend办法还有一个特色便是 能够经过第一个参数操控兼并方针时为深仿制仍是浅仿制。

语法: $ .extend( [deep ], target, object1 [, objectN ] )

deep 可选。 Boolean类型 指示是否深度兼并方针,默以为false。如果该值为true,且多个方针的某个同名特点也都是方针,则该”特点方针”的特点也将进行兼并。
target Object类型 方针方针,其他方针的成员特点将被附加到该方针上。
object1 可选。 Object类型 第一个被兼并的方针。
objectN 可选。 Object类型 第N个被兼并的方针。

2.完成

function extend() {
  let deep = false  // 默以为浅仿制
  let length = arguments.length
  let target = arguments[0] || {}
  let i = 1  
  let options;
  //用户开启了深仿制
  if(typeof target == 'boolean') {
    deep = target
    target = arguments[i] || {}
    i++
  }
  if(typeof target !== 'object') {
    target = {}
  }
  for(;i< length; i++){
    options = arguments[i]
    if(options != null) {
      for(let key in options) {
        //方针特点值
        let src = target[key]
        //要仿制的方针特点值
        let copy = options[key]
        if(deep && copy && typeof copy == 'object'){
          target[key] = extend(deep,src,copy) // 深仿制
        }else if (copy !== undefined){
          target[key] = copy // 浅仿制
       }
      }
    }
  }
  return target
}
let obj1 = {
  a: 1,
  b:{b1:1,b2:2},
  e:{d:2}
}
let obj2 = {
  b:{b1:3,b2:4},
  c:3
}
let obj3 = {
  d:4
}
let newObj = extend(false, {},obj1, obj2, obj3) //浅仿制
let newObj1 = extend(true, {},obj1, obj2, obj3) // 深仿制
obj2.b.b1 = 33
obj2.b.b2 = 33
obj1.e.d = 0
console.log(newObj); // { a: 1, b: { b1: 33, b2: 33 }, e: { d: 0 }, c: 3, d: 4 }
console.log(newObj1); // { a: 1, b: { b1: 3, b2: 4 }, e: { d: 2 }, c: 3, d: 4 }