1-js對象/數(shù)組的深拷貝和淺拷貝

JavaScript有兩種數(shù)據(jù)類型

基礎(chǔ)數(shù)據(jù)類型(Undefined佩厚、Null声功、Boolean惰聂、Number 和 String). 變量是直接按值存放的,存放在棧內(nèi)存中的簡單數(shù)據(jù)段芝薇,可以直接訪問。

引用數(shù)據(jù)類型(Array作儿、Object)洛二,變量保存的是一個指針。當(dāng)需要訪問引用類型時,先獲得地址指針灭红,在從內(nèi)存中取得數(shù)據(jù)侣滩。

JavaScript存儲對象都是存地址的,所以淺拷貝會導(dǎo)致 obj1 和obj2 指向同一塊內(nèi)存地址变擒。改變了其中一方的內(nèi)容君珠,都是在原來的內(nèi)存上做修改會導(dǎo)致拷貝對象和源對象都發(fā)生改變,而深拷貝是開辟一塊新的內(nèi)存地址娇斑,將原對象的各個屬性逐個復(fù)制進(jìn)去策添。對拷貝對象和源對象各自的操作互不影響。


淺復(fù)制:

淺復(fù)制是復(fù)制引用毫缆,復(fù)制后的引用都是指向同一個對象的實例唯竹,彼此之間的操作會互相影響。(對于直接賦值是不會影響的)

如圖:

1基礎(chǔ)數(shù)據(jù)類型的淺復(fù)制

Object.assign() 方法可以把任意多個的源對象自身的可枚舉屬性拷貝給目標(biāo)對象苦丁,然后返回目標(biāo)對象浸颓。

對于深度克隆,我們需要使用其他替代方法旺拉,因為Object.assign()復(fù)制屬性值产上。如果源值是對象的引用,則它僅復(fù)制該引用值蛾狗。 ?

2 object.assign()

深復(fù)制:

Array的slice和concat方法

不修改原數(shù)組晋涣,只會返回一個淺復(fù)制了原數(shù)組中的元素的一個新數(shù)組。之所以把它放在深拷貝里沉桌,是因為它看起來像是深拷貝谢鹊。而實際上它是淺拷貝。 類似于Object.assign()

JSON對象的parse和stringify

JSON對象parse方法可以將JSON字符串反序列化成JS對象留凭,stringify方法可以將JS對象序列化成JSON字符串佃扼,借助這兩個方法,也可以實現(xiàn)對象的深拷貝冰抢。


3松嘶、JSON.parse / JSON.stringify?

但是對于正則表達(dá)式類型、函數(shù)類型等無法進(jìn)行深拷貝(而且會直接丟失相應(yīng)的值)挎扰。還有一點不好的地方是它會拋棄對象的constructor翠订。也就是深拷貝之后,不管這個對象原來的構(gòu)造函數(shù)是什么遵倦,在深拷貝之后都會變成Object尽超。同時如果對象中存在循環(huán)引用的情況也無法正確處理。


4梧躺、jQuery.extend()方法源碼實現(xiàn)

jQuery的源碼 - src/core.js #L121源碼及分析如下:

jQuery.extend = jQuery.fn.extend = function() { //給jQuery對象和jQuery原型對象都添加了extend擴(kuò)展方法

? var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},

? i = 1,

? length = arguments.length,

? deep = false;

? //以上其中的變量:options是一個緩存變量似谁,用來緩存arguments[i]傲绣,name是用來接收將要被擴(kuò)展對象的key,src改變之前target對象上每個key對應(yīng)的value巩踏。

? //copy傳入對象上每個key對應(yīng)的value秃诵,copyIsArray判定copy是否為一個數(shù)組,clone深拷貝中用來臨時存對象或數(shù)組的src塞琼。

? // 處理深拷貝的情況

? if (typeof target === "boolean") {

? ? deep = target;

? ? target = arguments[1] || {};

? ? //跳過布爾值和目標(biāo)

? ? i++;

? }

? // 控制當(dāng)target不是object或者function的情況

? if (typeof target !== "object" && !jQuery.isFunction(target)) {

? ? target = {};

? }

? // 當(dāng)參數(shù)列表長度等于i的時候菠净,擴(kuò)展jQuery對象自身。

? if (length === i) {

? ? target = this; --i;

? }

? for (; i < length; i++) {

? ? if ((options = arguments[i]) != null) {

? ? ? // 擴(kuò)展基礎(chǔ)對象

? ? ? for (name in options) {

? ? ? ? src = target[name];

? ? ? ? copy = options[name];

? ? ? ? // 防止永無止境的循環(huán)彪杉,這里舉個例子毅往,

? ? ? ? ? ? // 如 var a = {name : b};

? ? ? ? ? ? // var b = {name : a}

? ? ? ? ? ? // var c = $.extend(a, b);

? ? ? ? ? ? // console.log(c);

? ? ? ? ? ? // 如果沒有這個判斷變成可以無限展開的對象

? ? ? ? ? ? // 加上這句判斷結(jié)果是 {name: undefined}

? ? ? ? if (target === copy) {

? ? ? ? ? continue;

? ? ? ? }

? ? ? ? if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {

? ? ? ? ? if (copyIsArray) {

? ? ? ? ? ? copyIsArray = false;

? ? ? ? ? ? clone = src && jQuery.isArray(src) ? src: []; // 如果src存在且是數(shù)組的話就讓clone副本等于src否則等于空數(shù)組。

? ? ? ? ? } else {

? ? ? ? ? ? clone = src && jQuery.isPlainObject(src) ? src: {}; // 如果src存在且是對象的話就讓clone副本等于src否則等于空數(shù)組派近。

? ? ? ? ? }

? ? ? ? ? // 遞歸拷貝

? ? ? ? ? target[name] = jQuery.extend(deep, clone, copy);

? ? ? ? } else if (copy !== undefined) {

? ? ? ? ? target[name] = copy; // 若原對象存在name屬性攀唯,則直接覆蓋掉;若不存在渴丸,則創(chuàng)建新的屬性侯嘀。

? ? ? ? }

? ? ? }

? ? }

? }

? // 返回修改的對象

? return target;

};

jQuery的extend方法使用基本的遞歸思路實現(xiàn)了淺拷貝和深拷貝,但是這個方法也無法處理源對象內(nèi)部循環(huán)引用曙强,例如:

var a = {"name":"aaa"};

var b = {"name":"bbb"};

a.child = b;

b.parent = a;

$.extend(true,{},a);//直接報了棧溢出残拐。Uncaught RangeError: Maximum call stack size exceeded

5、自己動手實現(xiàn)一個拷貝方法

(function ($) {

? ? 'use strict';

? ? var types = 'Array Object String Date RegExp Function Boolean Number Null Undefined'.split(' ');

function type () {

? return Object.prototype.toString.call(this).slice(8, -1);

}

for (var i = types.length; i--;) {

? ? $['is' + types[i]] = (function (self) {

? ? ? ? return function (elem) {

? ? ? ? ? return type.call(elem) === self;

? ? ? ? };

? ? })(types[i]);

}

? ? return $;

})(window.$ || (window.$ = {}));//類型判斷

function copy (obj,deep) {

? ? if ($.isFunction(obj)) {

? ? return new Function("return " + obj.toString())();

? ? } else if (obj === null || (typeof obj !== "object")) {

? ? ? ? return obj;

? ? } else {

? ? ? ? var name, target = $.isArray(obj) ? [] : {}, value;

? ? ? ? for (name in obj) {

? ? ? ? ? ? value = obj[name];

? ? ? ? ? ? if (value === obj) {

? ? ? ? ? ? continue;

? ? ? ? ? ? }

? ? ? ? ? ? if (deep) {

? ? ? ? ? ? ? ? if ($.isArray(value) || $.isObject(value)) {

? ? ? ? ? ? ? ? ? ? target[name] = copy(value,deep);

? ? ? ? ? ? ? ? } else if ($.isFunction(value)) {

? ? ? ? ? ? ? ? ? ? target[name] = new Function("return " + value.toString())();

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? target[name] = value;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? } else {

? ? ? ? ? ? target[name] = value;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return target;

? ? } ? ? ? ?

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碟嘴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子囊卜,更是在濱河造成了極大的恐慌娜扇,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栅组,死亡現(xiàn)場離奇詭異雀瓢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)玉掸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門刃麸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人司浪,你說我怎么就攤上這事泊业。” “怎么了啊易?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵吁伺,是天一觀的道長。 經(jīng)常有香客問我租谈,道長篮奄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮窟却,結(jié)果婚禮上昼丑,老公的妹妹穿的比我還像新娘。我一直安慰自己夸赫,他們只是感情好菩帝,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著憔足,像睡著了一般胁附。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滓彰,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天控妻,我揣著相機(jī)與錄音,去河邊找鬼揭绑。 笑死弓候,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的他匪。 我是一名探鬼主播菇存,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼邦蜜!你這毒婦竟也來了依鸥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤悼沈,失蹤者是張志新(化名)和其女友劉穎贱迟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體絮供,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡衣吠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壤靶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缚俏。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖贮乳,靈堂內(nèi)的尸體忽然破棺而出忧换,到底是詐尸還是另有隱情,我是刑警寧澤塘揣,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布包雀,位于F島的核電站,受9級特大地震影響亲铡,放射性物質(zhì)發(fā)生泄漏才写。R本人自食惡果不足惜葡兑,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赞草。 院中可真熱鬧讹堤,春花似錦、人聲如沸厨疙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽葬毫。三九已至,卻和暖如春闯捎,著一層夾襖步出監(jiān)牢的瞬間撒蟀,已是汗流浹背叙谨。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留保屯,地道東北人手负。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像姑尺,于是被迫代替她去往敵國和親竟终。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • /*! jQuery JavaScript Library v1.4.2 http://jquery.com/ C...
    ssttIsme閱讀 1,948評論 2 0
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5切蟋? 答:HTML5是最新的HTML標(biāo)準(zhǔn)统捶。 注意:講述HT...
    kismetajun閱讀 27,482評論 1 45
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,030評論 0 2
  • 過去的,永遠(yuǎn)回不去柄粹。 忘記的瘾境,用錢也買不回來。 所以人生經(jīng)歷镰惦,就是最寶貴的財富。 不要讓自己暮年回望犬绒,才發(fā)覺什么都...
    茶景閱讀 310評論 4 1
  • 今天坐高鐵旺入,竟然有15塊的套餐,要了一份凯力,吃起來味道還不賴茵瘾,跟飛機(jī)餐很像。以前讀書時咐鹤,舍不得坐臥鋪拗秘,一路80個小時...
    青三1219閱讀 578評論 0 51