轉(zhuǎn)載于:https://www.cnblogs.com/136asdxxl/p/8645750.html
一、js 數(shù)據(jù)類型
javaScritp的數(shù)據(jù)類型有:數(shù)值類型黍图、字符串類型厨喂、布爾類型和措、null、undefined杯聚、對象(數(shù)組臼婆、正則表達式、日期幌绍、函數(shù))颁褂,大致分成兩種:基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,
其中:
(1)基本數(shù)據(jù)類型:數(shù)值傀广、字符串颁独、布爾、null伪冰、undefined (值類型
(2)復(fù)雜(復(fù)合)數(shù)據(jù)類型:對象 (引用類型)
基本數(shù)據(jù)類型保存在棧內(nèi)存誓酒,引用類型保存在堆內(nèi)存中。根本原因在于保存在棧內(nèi)存的必須是大小固定的數(shù)據(jù),引用類型的大小不固定靠柑,只能保存在堆內(nèi)存中寨辩,但是可以把它的地址寫在棧內(nèi)存中以供我們訪問。
如果是基本數(shù)據(jù)類型歼冰,則按值訪問靡狞,操作的就是變量保存的值;如果是引用類型的值隔嫡,我們只是通過保存在變量中的引用類型的地址來操作實際對象甸怕。
var a = 1;//定義了一個number類型
var obj1 = {//定義了一個object類型
name:'obj'
};
1、基本類型的復(fù)制
var a = 1;
var b = a;//復(fù)制
console.log(b)//1
a = 2;//改變a的值
console.log(b)//1
賦值的時候腮恩,在棧內(nèi)存中重新開辟內(nèi)存梢杭,存放變量b,所以在棧內(nèi)存中分別存放著變量a秸滴、b各自的值武契,修改時互不影響。
2缸榛、引用類型的復(fù)制
var color1 = ['red','green'];
var color2 = color1;//復(fù)制
console.log(color2)//['red','green'];
color1.push('black') ;//改變color1的值
console.log(color2)//['red','green','black']
color1與color2指向堆內(nèi)存中同一地址的同一對象吝羞,復(fù)制的只是引用地址。
二内颗、深淺拷貝 :
淺拷貝只復(fù)制指向某個對象的指針钧排,而不復(fù)制對象本身,新舊對象還是共享同一塊內(nèi)存均澳。但深拷貝會另外創(chuàng)造一個一模一樣的對象恨溜,新對象跟原對象不共享內(nèi)存,修改新對象不會改到原對象找前。
1糟袁、淺拷貝
淺拷貝只是拷貝基本類型的數(shù)據(jù),如果父對象的屬性等于數(shù)組或另一個對象躺盛,那么實際上项戴,子對象獲得的只是一個內(nèi)存地址,因此存在父對象被篡改的可能槽惫,淺拷貝只復(fù)制指向某個對象的指針周叮,而不復(fù)制對象本身,新舊對象還是共享同一塊內(nèi)存界斜。
var Nation = {
nation: '中國'
};function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
return c;
}
var Doctor = extendCopy(Nation);
Doctor.career = '醫(yī)生';
Doctor.nation = '美國';
console.log(Doctor.nation); // 美國
console.log(Nation.nation); // 中國
console.log(Doctor.career); // 醫(yī)生
console.log(Doctor.__proto_ === Nation.__proto_) // true
// 這里涉及到使用拷貝父對象的屬性實現(xiàn)繼承
var obj = {
a: "hello",
b:{
a: "world",
b: 21
},
c:["Bob", "Tom", "Jenny"],
d:function() {
alert("hello world");
}
}
var obj1 = simpleClone(obj);
console.log('obj1=>>>',obj1);
// 1仿耽、
obj1.c = ['mm', "Tom", "Jenny"]; // 一層,作為整體各薇,重寫项贺,全改變;改變屬性值,不改變原對象
console.log('obj=>>>',obj); //obj.c => ["Bob", "Tom", "Jenny"]
// 2开缎、
obj1.c[0] = 'mm'; // 淺拷貝時棕叫,改變屬性的屬性值,改變原對象
console.log('obj=>>>',obj); //obj.c => ["mm", "Tom", "Jenny"]
淺拷貝函數(shù):
function simpleClone(initalObj) {
var obj = {};
for ( var i in initalObj) {
obj[i] = initalObj[i];
}
return obj;
}
2啥箭、深拷貝
深拷貝就是能夠?qū)崿F(xiàn)真正意義上的數(shù)組和對象的拷貝谍珊。遞歸調(diào)用"淺拷貝"。(深拷貝會另外創(chuàng)造一個一模一樣的對象急侥,新對象跟原對象不共享內(nèi)存,修改新對象不會改到原對象)
深拷貝函數(shù):
寫法一:
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i];
// 避免相互引用對象導(dǎo)致死循環(huán)侮邀,如initalObj.a = initalObj的情況
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
寫法二:
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i];
// 避免相互引用對象導(dǎo)致死循環(huán)坏怪,如initalObj.a = initalObj的情況
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
寫法三:
也可以通過利用 JSON 對象中的 parse 和 stringify 方法,將一個對象轉(zhuǎn)換為字符串绊茧,賦給新的對象控妻,再轉(zhuǎn)回JSON對象装获。
三、深拷貝的應(yīng)用實例
// jquery 有提供一個$.extend可以用來做 Deep Copy。
var $ = require('jquery');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);
// false
// 函數(shù)庫lodash覆旭,有提供_.cloneDeep用來做 Deep Copy。
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false