一、前言
在
js
中妖啥,變量的類型可以大致分成兩種:基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,其中基本數(shù)據(jù)類型指的是簡單的數(shù)據(jù)段,包括:
undefined
Null
Boolean
Number
-
String
(字符串在一些其他語言中是被當(dāng)做對(duì)象使用的,屬于引用類型俱笛,但在js
里是基本類型)
而引用類型的值指的是可能包含多個(gè)值的對(duì)象。本質(zhì)上传趾,是因?yàn)榛緮?shù)據(jù)類型保存在棧內(nèi)存,而引用類型保存在堆內(nèi)存中迎膜。為什么要分兩種保存方式呢? 根本原因在于保存在棧內(nèi)存的必須是大小固定的數(shù)據(jù)浆兰,引用類型的大小不固定磕仅,只能保存在堆內(nèi)存中,但是我們可以把它的地址寫在占內(nèi)存中以供我們訪問
var a = 1;//定義了一個(gè)number類型
var obj1 = {//定義了一個(gè)objr類型
name:'obj'
};
在執(zhí)行這段代碼后簸呈,內(nèi)存空間里是這樣的
因?yàn)檫@種保存方式的存在榕订,所以我們在操作變量的時(shí)候,如果是基本數(shù)據(jù)類型蜕便,則按值訪問劫恒,操作的就是變量保存的值;如果是引用類型的值轿腺,我們只是通過保存在變量中的引用類型的地址類操作實(shí)際對(duì)象两嘴。從而也引出了所謂的深淺復(fù)制問題
二、淺拷貝
方法一
// 假設(shè)有兩個(gè)對(duì)象
var objA = {
a: 'aa',
b: 'bb'
};
var objB = {};
// 現(xiàn)在想把對(duì)象A的值復(fù)制給B吃溅,由于對(duì)象A的兩個(gè)值都是原始類型溶诞,用淺復(fù)制即可
function copy(sub, sup) {
for (var key in sup) {
sub[key] = sup[key];
}
}
copy(objB, objA);
方法二
Object.assign() (兼容性不好)
方法三
_.clone()
方法四
數(shù)組中
concat
和slice
方法
方法五
ES6展開運(yùn)算
var arr = [{name:'poetries',age:22}]
var target = [...arr]
三、深拷貝
簡單來說深復(fù)制就是當(dāng)遇到值是對(duì)象類型的時(shí)候就再運(yùn)行一遍復(fù)制
方法一 JSON.parse(JSON.stringify(obj))
簡單粗暴又有點(diǎn)
dirty
决侈,但是能滿足日常需求螺垢,只能處理json
能理解的數(shù)據(jù)格式,當(dāng)然不包括函數(shù)了赖歌,性能也沒有特別好
方法二 lodash —— _.cloneDeep()
很好地兼容了ES6的新引用類型枉圃,而且處理了環(huán)型對(duì)象的情況
方法三 jQuery —— .extend()
源碼適合初學(xué)者學(xué)習(xí),比較好理解
方法四 自己實(shí)現(xiàn)一個(gè)
function deepCopy (obj) {
var result;
//引用類型分?jǐn)?shù)組和對(duì)象分別遞歸
if (Object.prototype.toString.call(obj) == '[object Array]') {
result = []
for (i = 0; i < obj.length; i++) {
result[i] = deepCopy(obj[i])
}
} else if (Object.prototype.toString.call(obj) == '[object Object]') {
result = {}
for (var attr in obj) {
result[attr] = deepCopy(obj[attr])
}
}
//值類型直接返回
else {
return obj
}
return result
}