1. js深拷貝
js深拷貝簡單對象的拷貝可以用JSON.stringify() 和 JSON.parse() 實現, 但是如果想要正確拷貝方法和原型就需要遍歷對象, 用ES6語法實現方法如下:
let FengUtil = (()=> {
/**
* 獲取obj的類型返回值首字母為大寫
* @param {*} obj
*/
let getType = (obj)=> {
let type = Object.prototype.toString.call(obj);
return /object\s(.*)]/.exec(type)[1];
};
/**
* 判斷對象是否為 type 類型
* @param {*} obj
* @param {*} type 小寫
*/
let isType = (obj, type)=>{
obj = getType(obj).toLowerCase();
return obj === type;
};
/**
* 深拷貝obj對象包括方法, 注意箭頭函數內的this指針無法正確拷貝
* @param {*} obj
*/
let deepCopy = (obj) => {
// 若不是對象類型或是null對象,直接輸出
if (typeof obj !== 'object' || obj === null) {
return obj
}
// 根據obj原型創建新對象
let target = Object.create(obj);
// 根據類型遞歸copy屬性到新對象
for (let i in obj) {
if (typeof obj[i] === 'object') {
target[i] = deepCopy(obj[i]);
}else if (typeof obj[i] === 'function') {
// function 類型不用拷貝
continue;
} else {
target[i] = obj[i];
}
}
return target;
};
return {
getType: getType,
isType: isType,
deepCopy: deepCopy
}
})();
經測試發現箭頭函數內的this指針無法正確copy
測試方法如下:
class Person {
constructor() {
this.name = 'defaultName';
this.age = 0;
this.children = [{name: 'kindy', age:8}, {name:'bily', age:10}];
}
speak() {
console.log('I am ' + this.name + ', I am speaking.');
};
repeat() {
console.log('I am ' + this.name + ', I am repeating.');
};
}
class Workman extends Person {
constructor() {
super();
this.job = 'defaultJob';
this.arrowFunc = () => {
console.log('arrow func invorked');
}
this.work = () => {
console.log('Infact I am ' + this.name);
this.speak();
console.log('I am working.');
};
}
walk() {
console.log('Infact I am ' + this.name);
this.repeat();
console.log('I am walking');
}
}
const worker1 = new Workman();
const child = new Workman();
child.name = 'lilei';
worker1.children.push(child);
const worker2 = FengUtil.deepCopy(worker1);
console.log('******測試對對象原型拷貝******');
console.log(worker1.__proto__);
console.log(worker2.__proto__);
// 改變拷貝對象的屬性和源對象屬性
worker1.name = 'worker1';
worker2.name = 'worker2';
console.log('******測試對方法和箭頭函數拷貝******');
console.log(worker2);
worker2.work();
worker2.walk();
console.log('******測試對象型屬性拷貝******');
const childOf1 = worker1.children[2];
childOf1.name = 'modifiedName';
console.log(childOf1);
const childOf2 = worker2.children[2];
console.log(childOf2);
附另外一種深拷貝方法, 缺點是無法實現對原型的拷貝, 另外對方法拷貝存在問題
/**
* 將obj對象傳入,return一個復制后的對象出來
* @param {*} obj
*/
let deepCopy_other = (obj) => {
// 若不是對象類型或是null類型,直接輸出
if (typeof obj !== 'object' || obj === null) {
return obj
}
let i;
// 根據目標是Array類型還是object來設置目標參數的類型
let target = FengUtil.isType(obj, 'array') ? [] : {};
for (i in obj) {
// 判斷當前復制的對象是否為對象類型數據
if (typeof obj[i] === 'object') {
deepCopy(obj[i]); // has bug of this line
}
target[i] = obj[i]
}
return target
};
2. js數據類型總結
********typeof********
[] is: object
{} is: object
null is: object
undefined is:undefined
"str" is: string
1 is: number
1.1 is: number
********FengUtil.getType********
[] is: Array
{} is: Object
undefined is:Null
"str" is: Undefined
"str" is: String
1 is: Number
1.1 is: Number