示例
值類型
let a = 100;
let b = a;
a = 200;
console.log(b); // 100 (互不影響)
引用類型
let a = { age: 20 };
let b = a;
a.age= 21;
console.log(b.age); // 21 (b.age隨a.age的改變而改變)
存儲方式
值類型
js變量存儲在棧中,至於怎么存儲咱先不管(畢竟我也不懂),這是js引擎的事情。
如圖所示,key為變量名,value為存儲內容,值類型變量的值直接存儲在value中,a的值改變后並不會影響b的值。
引用類型
在棧中,引用類型存儲的是內存地址,同時內存地址指向堆中的值,
簡單地講:引用類型a -> 內存地址1 -> a的值,此時若執行let b = a;
,則是把b的內存地址指向了a的內存地址,而這個內存地址指向同一個值,所以a的值改變的時候,b的值也隨之改變。
為什么引用類型要搞個內存地址?
眾所周知最常見的引用類型是對象和數組,數組長度和對象屬性數量是沒有限制的,甚至可以嵌套,如果像存儲值類型那樣存儲引用類型(沒有內存地址,直接存儲在棧中),那計算機怕是要炸了。
常見值類型和引用類型
// 常見值類型
let a; // undefined
const n = 100; // Number
const s = '100'; // String
const b = true; // Boolean
const s = Symbol('s') // Symbol(es6)
// 常見引用類型
const obj = { value: 100 }; // Object
const arr = [ 1, 2, 3 ]; // Array
const n = null; // 特殊引用類型,指針指向空地址
function fn() {} // 特殊引用類型,但不用於存儲數據,所以不考慮深拷貝淺拷貝的問題
深拷貝
-
JSON.parse(JSON.stringify(obj))
最簡單的方式,但會忽略undefined,function,RegExp -
Object.assign()或解構賦值(
const a = {...obj}
,const b = [...arr]
)
注意這里並不是深拷貝,只是當對象或數組只有一層沒有嵌套的時候可以使用此方式來進行拷貝
const obj1 = { a: 1, b: 2, c: 3, d: 4}; // 可以使用
const obj2 = { a: 1, b: { c: 3 }, d: 4 }; // 不可使用
- 遞歸
const deepCopy = obj => {
let copy = Array.isArray(obj) === true ? [] : {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object') {
copy[key] = deepCopy(obj[key])
} else {
copy[key] = obj[key]
}
}
}
return copy
}