前言
上一篇一道面試題引發的js資料型別傳參思考,研究了下js資料在記憶體中的儲存,在最後自然而然的想到了深拷貝和淺拷貝,篇幅所限,就放在這裡了。
何為淺拷貝
沿用上一篇的圖
var obj1 = {x:1, y:2};
var obj2 = obj1;
obj2.x = 3;
console.log(obj1); // {x: 3, y: 2}
複製程式碼
形如上面這個例子,簡單的把物件obj1賦值給obj2,他們在記憶體中都指向相同的堆區,改變任何一個都會影響另一個,這就是淺拷貝:賦值後的資料會相互影響
深拷貝
為了解決淺拷貝的問題,自然引申出了深拷貝:賦值後的資料彼此獨立,不相互影響。即obj2擁有obj1的初始資料,但obj2的資料放在堆區的另一個位置。
深拷貝原理很簡單:遞迴遍歷物件,一一賦值
直接上完整版程式碼:
function deepClone(from, to) {
var record = {} // 記錄引用,解決物件迴圈引用的問題
function innerDP(from, to) {
for (var i in from) {
if (!from.hasOwnProperty(i)) {
// for...in會遍歷到原型鏈上的可列舉屬性,hasOwnProperty只訪問物件例項本身的屬性
continue
}
if (from[i] && typeof from[i] === 'object' && Object.keys(from[i]).length > 0 && !(record[i] && record[i] === from[i])) {
to[i] = {}
record[i] = from[i]
innerDP(from[i], to[i])
} else {
to[i] = from[i]
}
}
}
innerDP(from, to)
}
var staff1 = {
name: '張三',
company: {
title: '總監',
cid: '10006',
wage: 50000,
service: [1, 2, 3, {level: 'gold'}],
},
age: undefined,
x: null,
y: '',
getName: function () {
return this.name
}
}
var staff2 = {}
deepClone(staff1, staff2)
console.log('staff2拷貝staff1成功:', staff2)
staff2.x = 3
staff2.company.title = '程式猿'
staff2.company.service[3].level = 'silver'
console.log('staff2改變:', staff2)
console.log('staff1是否被影響:', staff1)
var btn1 = $('#btn1') // $('#btn1').context迴圈引用
var btn2 = {}
deepClone(btn1, btn2)
// btn2.length = 2
console.log(btn2)
console.log(btn1)
}
複製程式碼
物件迴圈引用的問題
形如這樣的迴圈引用物件:
var a = {}; var b = {a: a}; a.b = b; // a中有b,b中有a,無限巢狀 複製程式碼
深拷貝時會導致堆溢位報錯:Uncaught RangeError: Maximum call stack size exceeded
所以deepClone採用了record記錄:!(record[i] && record[i] === from[i]) 複製程式碼
型別判斷
Object.prototype.toString.call方法
萬物皆物件,Object.prototype.toString.call(value)返回的格式都是"[Object 型別]"
function valueType(value) {
var str = Object.prototype.toString.call(value)
str = str.split(' ')[1].replace(']', '')
return str
}
console.log(valueType(1)); // "Number"
console.log(valueType('1')); // "String"
console.log(valueType(undefined)); // "Undefined"
console.log(valueType(false)); // "Boolean"
console.log(valueType(Function)); // "Function"
console.log(valueType(null)); // "Null"
console.log(valueType([])); // "Array"
console.log(valueType([])); // "Object"
console.log(valueType($('#btn1'))); // "Object"
console.log(valueType($('#btn1').context)); // "HTMLDocument"
複製程式碼
typeof判斷
typeof 1; // "number"
typeof '1'; // "string"
typeof undefined; // "undefined"
typeof false; // "boolean"
typeof Function; // "function"
typeof null; // "object"
typeof []; // "object"
typeof {}; // "object"
複製程式碼