|| Shallow & Deep Copy || Recursion || Lot's of Concept || JS 
CodeThe Array slice() method returns selected elements in an array as a new array. It selects from a given start, up to a (not inclusive) given end. This method

# Code
```javascript []
/**
 * @param {Array} arr
 * @param {number} depth
 * @return {Array}
 */

var flat = function (arr, n) {
    if(n === 0){
        console.log(arr);
        return arr.slice()
    }  // it create shallow copy of array
    // Q. Why we are using slice method ...
    // Ans. This is because in case we have to modify original array then it create some conflict.

    let flatarr = [];

    for(let i=0; i<arr.length; i++){
        if(Array.isArray(arr[i])){ // this check that at index i there is array or not
            const nested = flat(arr[i], n-1); //if n=0 then it hit base case and return as it is...
            flatarr.push(...nested);
        }else{
            flatarr.push(arr[i]);
        }
    }
    // [1,2,3,[4,5,6],[7,8,[9,10,11],12],[13,14,15]]

    return flatarr;

};
```

The Array slice() method returns selected elements in an array as a new array. It selects from a given start, up to a (not inclusive) given end. This method does not change the original array, enabling non-destructive extraction of array segments.

```
// Syntax:
// arr.slice(begin, end);
```


Use of flat function
```
// const myArr = [1, 2, [3, [4, 5, 6], 7], 8];
// const newArr = myArr.flat(2);
// console.log(newArr);
```
# Shallow copy & Deep Copy
*JavaScripts has two data types, primitive data type and reference data type. The object comes under reference data type which means it follows copying data using its memory location i.e., copied by reference type.*

Let's see what problems are caused while copying an object from another object and when we have to use shallow and deep copy concepts.


```
let obj1 = {
 name : "XYZ",
  address : {
   city : "Mumbai",
    state : "Maharashtra"
  }
}

// copying first object into new object i.e, obj2
let obj2 = obj1;

obj2.name = "QWERTY"

console.log("Object 1", obj1.name);
console.log("Object 2", obj2.name);

// result
"Object 1", "QWERTY"
"Object 2", "QWERTY"
```

**So in the above example, if we changed the name property from obj2 it will change the obj1 property as well. To resolve this we can use shallow and deep copy methods.**

1. Shallow copy ---------------------------------->
// In short free it from reference from single(first) level
```
let originalObj = {
 name : "XYZ",
  address : {
   city : "Mumbai",
    state : "Maharashtra"
  }
}

//Shallow copy first way
//let copyObj = Object.assign({},originalObj);

//Shallow copy second way
let copyObj = {...originalObj};

copyObj.name = "QWERTY"
copyObj.address.city = "Pune"

console.log("originalObj name", originalObj.name);
console.log("copyObj name", copyObj.name);
console.log("originalObj city", originalObj.address.city);
console.log("copyObj city", copyObj.address.city);
```

**We copied the originalObj into the copyObj and changed the name of the copyObj. originalObj name will remain unchanged. i.e.**
Result
```
"originalObj name", "XYZ"
"copyObj name", "QWERTY"
"originalObj city", "Pune"
"copyObj city", "Pune"
```

**But shallow copy will work only first level. So when we change city from copyObj, it will change originalObj as well since it is on the second level.**




2. Deep copy --------------------------------------->
// In short free it from reference from nested level
// To solve the shallow copy issue we can use deep copy concept.
```
let originalObj = {
 name : "XYZ",
  address : {
   city : "Mumbai",
    state : "Maharashtra"
  },
  checkFun : function(){
     return 100;
  }
}

let copyObj = JSON.parse(JSON.stringify(originalObj));

copyObj.name = "QWERTY"
copyObj.address.city = "Pune"

console.log("originalObj name", originalObj.name);
console.log("originalObj city", originalObj.address.city);
console.log("copyObj", copyObj);

//result
"originalObj name", "XYZ"
"originalObj city", "Mumbai"
"copyObj", {
  address: {
    city: "Pune",
    state: "Maharashtra"
  },
  name: "QWERTY"
}
```
In the above example, we can change all level values except checkFun property. checkFun is not available in the copied object.

To resolve this we have to use lodash library.
```
let copyObj = _.cloneDeep(originalObj)
console.log("copyObj", copyObj);

//result
"copyObj", {
  address: {
    city: "Mumbai",
    state: "Maharashtra"
  },
  checkFun: function(){
     return 100;
  },
  name: "XYZ"
}
```
['JavaScript']