深拷貝和淺拷貝的簡要詳解
在前端面試題過程中,會遇到一些可能是你見過,但是實際上並沒有運用過的問題。幾天前,我就遇到了這個淺拷貝和深拷貝的問題,特意騰出來一點時間來整理一下,希望能幫到一些有點小迷惑的同學。。。
深拷貝和淺拷貝的概念
深拷貝和淺拷貝是針對複雜資料型別來說的,淺拷貝只拷貝一層,而深拷貝是層層拷貝。
深拷貝複製變數值,對於非基本型別的變數,則遞迴至基本型別變數後,再複製。深拷貝後的物件與原來的物件是完全隔離的,互不影響,對一個物件的修改並不會影響另一個物件。
淺拷貝是會將物件的每個屬性進行依次複製,但是當物件的屬性值是引用型別時,實質複製的是其引用,當引用指向的值改變時也會跟著變化。
可以使用 for in、 Object.assign、 擴充套件運算子 … 、Array.prototype.slice()、Array.prototype.concat() 等
var array = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
var copyArray = array.slice();
copyArray[0].number = 100;
console.log(array);
console.log(copyArray);
let obj = {
name: ‘Yvette’,
age: 18,
hobbies: [‘reading’, ‘photography’]
}
let obj2 = Object.assign({}, obj);
let obj3 = {…obj};
obj.name = 'Jack';
obj.hobbies.push('coding');
console.log(obj);
console.log(obj2);
console.log(obj3);
由此可以看出淺拷貝只最第一層屬性進行了拷貝,當第一層的屬性值是基本資料型別時,新的物件和原物件互不影響,但是如果第一層的屬性值是複雜資料型別,那麼新物件和原物件的屬性值其指向的是同一塊記憶體地址。
1.深拷貝最簡單的實現是: JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj)) 是最簡單的實現方式,但是有一些缺陷:
物件的屬性值是函式時,無法拷貝。
原型鏈上的屬性無法拷貝
不能正確的處理 Date 型別的資料
不能處理 RegExp
會忽略 symbol
會忽略 undefined
var deepCopy = function(a) {
return JSON.parse(JSON.stringify(a));
}
a = {name:'aaa',people:{name: 'abc'}};b = deepCopy(a);b.people.name = 'def';
console.log(a,b)
a = [1,2, {name: 'aaa'}];b = deepCopy(a);b[2].name = 'bbb';
console.log(a,b)
a = {name:'aaa',fun:function(){console.log('fun');},nn: undefined};
b = deepCopy(a);
console.log(a,b)
1.上述的方法會忽略值為function以及undefined的欄位,而且對date型別的支援也不太友好
2.上述方法只能克隆原始物件自身的值,不能克隆它繼承的值
function Person (name) {
this.name = name
}
var a = new Person('王二');
var b = deepCopy(a);
console.log(a.constructor == Person); // true
console.log(b.constructor == Object); // true
2.實現一個 deepClone 函式 (深拷貝,完美)
如果是基本資料型別,直接返回
如果是 RegExp 或者 Date 型別,返回對應型別
如果是複雜資料型別,遞迴。
考慮迴圈引用的問題
var show={
btn:"btn",
init:function(){
var that=this;
alert(this);
this.btn.click(function(){
that.change();
alert(this);
})
},
change:function(){
this.btn.css({'background':'green'});
person={
name:"king",
show:function(){
console.log(this.name)
}
}
}
}
function deepClone(obj, hash = new WeakMap()) { //遞迴拷貝
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (obj === null || typeof obj !== 'object') {
//如果不是複雜資料型別,直接返回
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
/**
* 如果obj是陣列,那麼 obj.constructor 是 [Function: Array]
* 如果obj是物件,那麼 obj.constructor 是 [Function: Object]
*/
let t = new obj.constructor();
hash.set(obj, t);
for (let key in obj) {
//遞迴
if (obj.hasOwnProperty(key)) {//是否是自身的屬性
t[key] = deepClone(obj[key], hash);
}
}
return t;
}
var show2 = cloneObject(show)
console.log(show2)
//遞迴函式
function cloneObject (obj) {
var newObj = {} //如果不是引用型別,直接返回
if (typeof (obj) !== 'object') {
return obj
}
//如果是引用型別,遍歷屬性
else{
for (var attr in obj) {
//如果某個屬性還是引用型別,遞迴呼叫
newObj[attr] = cloneObject(obj[attr])
}
}
return newObj
}
相關文章
- iOS深拷貝和淺拷貝iOS
- Java深拷貝和淺拷貝Java
- 物件深拷貝和淺拷貝物件
- JavaScript深拷貝和淺拷貝JavaScript
- js 淺拷貝和深拷貝JS
- js 深拷貝和淺拷貝JS
- JavaScript淺拷貝和深拷貝JavaScript
- js深拷貝和淺拷貝JS
- js的深拷貝和淺拷貝JS
- javaScript深拷貝和淺拷貝簡單梳理JavaScript
- 淺探js深拷貝和淺拷貝JS
- C++淺拷貝和深拷貝C++
- go slice深拷貝和淺拷貝Go
- JavaScript之深拷貝和淺拷貝JavaScript
- 聊聊物件深拷貝和淺拷貝物件
- ECMAScript-淺拷貝和深拷貝
- js之淺拷貝和深拷貝JS
- 深度解析深拷貝和淺拷貝
- Objective C淺拷貝和深拷貝Object
- java深克隆(深拷貝)和淺克隆(淺拷貝)Java
- vue深拷貝淺拷貝Vue
- VUE 中 的深拷貝和淺拷貝Vue
- 對淺拷貝和深拷貝的理解
- Python 擴充之詳解深拷貝和淺拷貝Python
- python 指標拷貝,淺拷貝和深拷貝Python指標
- 淺談深拷貝與淺拷貝?深拷貝幾種方法。
- 淺談Java中的淺拷貝和深拷貝Java
- jquery之物件拷貝深拷貝淺拷貝案例講解jQuery物件
- js實現深拷貝和淺拷貝JS
- js 陣列的淺拷貝和深拷貝JS陣列
- PHP中的淺拷貝和深拷貝薦PHP
- JS深拷貝與淺拷貝JS
- javascript 淺拷貝VS深拷貝JavaScript
- js 深拷貝 vs 淺拷貝JS
- python深拷貝和淺拷貝之簡單分析Python
- 物件的深拷貝與淺拷貝物件
- 深入淺出深拷貝與淺拷貝
- 深入淺出的“深拷貝與淺拷貝”