一劝术、 基本數(shù)據(jù)類型的拷貝(復(fù)制copy)深拷貝和淺拷貝?
深拷貝和淺拷貝是針對(duì)復(fù)雜數(shù)據(jù)類型來說的崭捍,淺拷貝只拷貝一層噪窘,而深拷貝是層層拷貝
基本數(shù)據(jù)類型? 值傳遞? ??
a = 1.1;b = a;b = 2; console.log(a,b)? ? ? ? ? ? ? ? ? ?Number
a = 'hello';b = a;b = 3; console.log(a,b)? ? ? ? ? ? ? ? ?String
a = false;b = a;b = 'sss'; console.log(a,b)? ? ? ? ? ? ??Boolean??
a = undefined;b = a;b = false; console.log(a,b)? ? ?Undefined? ??
?a = null;b = a;b = undefined; console.log(a,b)? ? ? ? Null
深拷貝
? 深拷貝復(fù)制變量值妆艘,對(duì)于非基本類型的變量植康,則遞歸至基本類型變量后旷太,再?gòu)?fù)制。 深拷貝后的對(duì)象與原來的對(duì)象是完全隔離的销睁,互不影響供璧,對(duì)一個(gè)對(duì)象的修改并不會(huì)影響另一個(gè)對(duì)象。
?淺拷貝
?淺拷貝是會(huì)將對(duì)象的每個(gè)屬性進(jìn)行依次復(fù)制冻记,但是當(dāng)對(duì)象的屬性值是引用類型時(shí)睡毒,實(shí)質(zhì)復(fù)制的是其引用,當(dāng)引用指向的值改變時(shí)也會(huì)跟著變化冗栗。
可以看出淺拷貝只最第一層屬性進(jìn)行了拷貝演顾,當(dāng)?shù)谝粚拥膶傩灾凳腔緮?shù)據(jù)類型時(shí),新的對(duì)象和原對(duì)象互不影響隅居,但是如果第一層的屬性值是復(fù)雜數(shù)據(jù)類型钠至,那么新對(duì)象和原對(duì)象的屬性值其指向的是同一塊內(nèi)存地址。
二胎源、復(fù)雜數(shù)據(jù)類型(object)的拷貝??地址傳遞
常用的復(fù)雜數(shù)據(jù)類型包括:{ }棉钧、[ ]、function(){} 涕蚤、Date(時(shí)間) 宪卿、RegExp 的诵、null(這個(gè)比較特殊)等
?1、我們依然用一的簡(jiǎn)單賦值(=)來進(jìn)行一遍操作(賦值)
? ?經(jīng)過實(shí)踐我們會(huì)發(fā)現(xiàn):
? ? ?1愧捕、當(dāng)類型為{}奢驯、[]的時(shí)候申钩,改變b的值次绘,a也會(huì)跟著一起變化。
? ? ?2撒遣、當(dāng)類型為Date邮偎、function、RegExp的時(shí)候义黎,a保持不變禾进。
? ?總結(jié):我們發(fā)現(xiàn){}或者[]時(shí),簡(jiǎn)單的賦值操作并不能實(shí)現(xiàn)它們的拷貝廉涕,只是改了b的指向泻云,使a和b都指向同一個(gè)引用,隨意改變一個(gè)狐蜕,都會(huì)影響另外一個(gè)的值宠纯。?
? ? // {}
? ? // a = {name: 'abc'};b = a;b.name = 'sss';
? ? // console.log(a,b)
? ? // // []
? ? // a = ['a','b','c'];b = a;b[1] = 'd';
? ? // console.log(a,b)
? ? // // function
? ? // a = function(){ alert('aaa'); };b = a;b = function(){ alert('bbb'); };
? ? // console.log(a.toString(),b.toString())
? ? // // Date
? ? // a = new Date('2018-10-11 00:00:00');b = a;b = new Date('1970-01-01 00:00:00');
? ? // console.log(a,b)
? ? // // RegExp
? ? // a = new RegExp('abc');b = a;b = new RegExp('aaa');
? ? // console.log(a,b)
? ? // 2、Object.assign 和 for in進(jìn)行{}和[]的拷貝(淺拷貝--只能拷貝一層)
? ? // Object.assign
? ? // a = {name: 'aaa'};b = Object.assign({}, a);
? ? // b.name = 'bbb';?
? ? // console.log(a,b)
? ? // a = [1,2,3];b = Object.assign([], a);b[1] = 4;?
? ? // console.log(a,b)
? ? // // for in
? ? // var copy = function(a) {
? ? //? var res = a.constructor();
? ? //? console.log(res)
? ? //? for(var key in a) {
? ? //? if(a.hasOwnProperty(key)) {
? ? //? ? res[key] = a[key];
? ? //? }
? ? //? }
? ? //? return res;
? ? // }
? ? // a = {name: 'aaa'};b = copy(a);b.name = 'bbb';?
? ? // console.log(a,b)
? ? // a = [1,2,3];b = copy(a);b[1] = 4;?
? ? // console.log(a,b)
? // a = {name:'aaa',people:{name: 'abc'}};b = Object.assign({}, a);b.people.name = 'def';
? // console.log(a,b)? ? ? ? ? ? ? ? ? ? ? ?
? // // for in
? //? var copy = function(a) {
? //? ? var res = a.constructor();
? //? ? for(var key in a) {
? //? ? if(a.hasOwnProperty(key)) {
? //? ? ? res[key] = a[key];
? //? ? }
? //? ? }
? //? ? return res;
? //? }
? // a = {name:'aaa',people:{name: 'abc'}};b = copy(a);b.people.name = 'def';
? // console.log(a,b)
? // a = [1,2, {name: 'aaa'}];b = Object.assign([], a);b[2].name = 'bbb';
? // console.log(a,b)
? // a = [1,2, {name: 'aaa'}];b = copy(a);b[2].name = 'bbb';
? // console.log(a,b)
? ? ? ?深拷貝和淺拷貝是針對(duì)復(fù)雜數(shù)據(jù)類型來說的层释,淺拷貝只拷貝一層婆瓜,而深拷貝是層層拷貝。
? 深拷貝
? ? ? 深拷貝復(fù)制變量值贡羔,對(duì)于非基本類型的變量廉白,則遞歸至基本類型變量后,再?gòu)?fù)制乖寒。 深拷貝后的對(duì)象與原來的對(duì)象是完全隔離的猴蹂,互不影響,對(duì)一個(gè)對(duì)象的修改并不會(huì)影響另一個(gè)對(duì)象楣嘁。
? ?淺拷貝
? ? ? ?淺拷貝是會(huì)將對(duì)象的每個(gè)屬性進(jìn)行依次復(fù)制磅轻,但是當(dāng)對(duì)象的屬性值是引用類型時(shí),實(shí)質(zhì)復(fù)制的是其引用马澈,當(dāng)引用指向的值改變時(shí)也會(huì)跟著變化瓢省。 可以使用 for in、 Object.assign痊班、 擴(kuò)展運(yùn)算符 ... 勤婚、Array.prototype.slice()、Array.prototype.concat() 等
// var array = [
? ? //? ? { number: 1 },
? ? //? ? { number: 2 },
? ? //? ? { number: 3 }
? ? // ];
? ? // var copyArray = array.slice();
? ? // copyArray[0].number = 100;
? ? // console.log(array);
? ? // console.log(copyArray);
? ? // let obj = {
? ? //? ? name: 'Yvette',
? ? //? ? age: 18,
? ? //? ? hobbies: ['reading', 'photography']
? ? // }
? ? // let obj2 = Object.assign({}, obj);
? ? // let obj3 = {...obj};
? ? // obj.name = 'Jack';
? ? // obj.hobbies.push('coding');
? ? // console.log(obj);
? ? // console.log(obj2);
? ? // console.log(obj3);
? ? ? ?可以看出淺拷貝只最第一層屬性進(jìn)行了拷貝涤伐,當(dāng)?shù)谝粚拥膶傩灾凳腔緮?shù)據(jù)類型時(shí)馒胆,新的對(duì)象和原對(duì)象互不影響缨称,但是如果第一層的屬性值是復(fù)雜數(shù)據(jù)類型,那么新對(duì)象和原對(duì)象的屬性值其指向的是同一塊內(nèi)存地址祝迂。
? ? ?1.深拷貝最簡(jiǎn)單的實(shí)現(xiàn)是: JSON.parse(JSON.stringify(obj))
? ? JSON.parse(JSON.stringify(obj)) 是最簡(jiǎn)單的實(shí)現(xiàn)方式睦尽,但是有一些缺陷:
? ? ?//對(duì)象的屬性值是函數(shù)時(shí),無(wú)法拷貝型雳。
? ? //? 原型鏈上的屬性無(wú)法拷貝
? ? //? 不能正確的處理 Date 類型的數(shù)據(jù)
? ? //? 不能處理 RegExp
? ? //? 會(huì)忽略 symbol
? ? //? 會(huì)忽略 undefined
遞歸函數(shù)
如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身当凡,這個(gè)函數(shù)就叫做遞歸函數(shù)
遞歸函數(shù):
? ? ? 實(shí)現(xiàn)一個(gè) deepClone 函數(shù) (深拷貝,完美)
? ? ? // 如果是基本數(shù)據(jù)類型纠俭,直接返回
? ? ? // 如果是 RegExp 或者 Date 類型沿量,返回對(duì)應(yīng)類型
? ? ? // 如果是復(fù)雜數(shù)據(jù)類型,遞歸冤荆。
? ? ? // 考慮循環(huán)引用的問題
? ? // var show={
? ? //? ? btn:"btn",
? ? //? ? init:function(){
? ? //? ? ? ? var that=this;
? ? //? ? ? ? alert(this);
? ? //? ? ? ? this.btn.click(function(){
? ? //? ? ? ? ? ? ? ? that.change();
? ? //? ? ? ? ? ? ? ? alert(this);
? ? //? ? ? ? })? ? ? ? ? ?
? ? //? ? },
? ? //? ? change:function(){
? ? //? ? ? ? this.btn.css({'background':'green'});
? ? //? ? ? ? person={
? ? //? ? ? ? ? name:"king",
? ? //? ? ? ? ? show:function(){
? ? //? ? ? ? ? ? console.log(this.name)
? ? //? ? ? ? ? }
? ? //? ? ? ? }
? ? //? ? }
? ? // }
? ? // function deepClone(obj, hash = new WeakMap()) { //遞歸拷貝
? ? //? ? if (obj instanceof RegExp) return new RegExp(obj);
? ? //? ? if (obj instanceof Date) return new Date(obj);
? ? //? ? if (obj === null || typeof obj !== 'object') {
? ? //? ? ? ? //如果不是復(fù)雜數(shù)據(jù)類型朴则,直接返回
? ? //? ? ? ? return obj;
? ? //? ? }
? ? //? ? if (hash.has(obj)) {
? ? //? ? ? ? return hash.get(obj);
? ? //? ? }
? ? ? ? /**
? ? ? ? * 如果obj是數(shù)組,那么 obj.constructor 是 [Function: Array]
? ? ? ? * 如果obj是對(duì)象钓简,那么 obj.constructor 是 [Function: Object]
? ? ? ? */
? ? //? ? let t = new obj.constructor();
? ? //? ? hash.set(obj, t);
? ? //? ? for (let key in obj) {
? ? //? ? ? ? //遞歸
? ? //? ? ? ? if (obj.hasOwnProperty(key)) {//是否是自身的屬性
? ? //? ? ? ? ? ? t[key] = deepClone(obj[key], hash);
? ? //? ? ? ? }
? ? //? ? }
? ? //? ? return t;
? ? // }
? ? // var show2 = cloneObject(show)
? ? // console.log(show2)
//遞歸函數(shù)
// function cloneObject (obj) {
? // var newObj = {}? //如果不是引用類型乌妒,直接返回
? // if (typeof (obj) !== 'object') {
? // ? return obj
? // }
? // //如果是引用類型,遍歷屬性
? // else{
? // for (var attr in obj) {
? // //如果某個(gè)屬性還是引用類型外邓,遞歸調(diào)用
? // ? newObj[attr] = cloneObject(obj[attr])
? // }
? // }
? // return newObj
// }