真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

javaScript中淺拷貝與深拷貝的區(qū)別是什么

今天就跟大家聊聊有關(guān)javaScript中淺拷貝與深拷貝的區(qū)別是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的潁上網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

1、javaScript的變量類型

(1)基本類型:

5種基本數(shù)據(jù)類型Undefined、Null、Boolean、Number 和 String,變量是直接按值存放的,存放在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段,可以直接訪問。

(2)引用類型:

存放在堆內(nèi)存中的對(duì)象,變量保存的是一個(gè)指針,這個(gè)指針指向另一個(gè)位置。當(dāng)需要訪問引用類型(如對(duì)象,數(shù)組等)的值時(shí),首先從棧中獲得該對(duì)象的地址指針,然后再?gòu)亩褍?nèi)存中取得所需的數(shù)據(jù)。

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

例如:數(shù)組拷貝

//淺拷貝,雙向改變,指向同一片內(nèi)存空間
var arr1 = [1, 2, 3];
var arr2 = arr1;
arr1[0] = 'change';
console.log('shallow copy: ' + arr1 + " ); //shallow copy: change,2,3
console.log('shallow copy: ' + arr2 + " ); //shallow copy: change,2,3

2、淺拷貝的實(shí)現(xiàn)

2.1、簡(jiǎn)單的引用復(fù)制

function shallowClone(copyObj) {
 var obj = {};
 for ( var i in copyObj) {
 obj[i] = copyObj[i];
 }
 return obj;
}
var x = {
 a: 1,
 b: { f: { g: 1 } },
 c: [ 1, 2, 3 ]
};
var y = shallowClone(x);
console.log(y.b.f === x.b.f);  // true

2.2、Object.assign()

Object.assign() 方法可以把任意多個(gè)的源對(duì)象自身的可枚舉屬性拷貝給目標(biāo)對(duì)象,然后返回目標(biāo)對(duì)象。Object.assign會(huì)跳過那些值為 null 或 undefined 的源對(duì)象。

var x = {
 a: 1,
 b: { f: { g: 1 } },
 c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f);  // true

3、深拷貝的實(shí)現(xiàn)

3.1、Array的slice和concat方法

Array的slice和concat方法不修改原數(shù)組,只會(huì)返回一個(gè)淺復(fù)制了原數(shù)組中的元素的一個(gè)新數(shù)組。之所以把它放在深拷貝里,是因?yàn)樗雌饋硐袷巧羁截?。而?shí)際上它是淺拷貝。原數(shù)組的元素會(huì)按照下述規(guī)則拷貝:

  • 如果該元素是個(gè)對(duì)象引用 (不是實(shí)際的對(duì)象),slice 會(huì)拷貝這個(gè)對(duì)象引用到新的數(shù)組里。兩個(gè)對(duì)象引用都引用了同一個(gè)對(duì)象。如果被引用的對(duì)象發(fā)生改變,則新的和原來的數(shù)組中的這個(gè)元素也會(huì)發(fā)生改變。

  • 對(duì)于字符串、數(shù)字及布爾值來說(不是 String、Number 或者 Boolean 對(duì)象),slice 會(huì)拷貝這些值到新的數(shù)組里。在別的數(shù)組里修改這些字符串或數(shù)字或是布爾值,將不會(huì)影響另一個(gè)數(shù)組。

如果向兩個(gè)數(shù)組任一中添加了新元素,則另一個(gè)不會(huì)受到影響。例子如下:

var array = [1,2,3]; 
var array_shallow = array; 
var array_concat = array.concat(); 
var array_slice = array.slice(0); 
console.log(array === array_shallow); //true 
console.log(array === array_slice); //false,“看起來”像深拷貝
console.log(array === array_concat); //false,“看起來”像深拷貝

可以看出,concat和slice返回的不同的數(shù)組實(shí)例,這與直接的引用復(fù)制是不同的。而從另一個(gè)例子可以看出Array的concat和slice并不是真正的深復(fù)制,數(shù)組中的對(duì)象元素(Object,Array等)只是復(fù)制了引用。如下:

var array = [1, [1,2,3], {name:"array"}]; 
var array_concat = array.concat();
var array_slice = array.slice(0);
array_concat[1][0] = 5; //改變array_concat中數(shù)組元素的值 
console.log(array[1]); //[5,2,3] 
console.log(array_slice[1]); //[5,2,3] 
array_slice[2].name = "array_slice"; //改變array_slice中對(duì)象元素的值 
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice

3.2、JSON對(duì)象的parse和stringify

JSON對(duì)象是ES5中引入的新的類型(支持的瀏覽器為IE8+),JSON對(duì)象parse方法可以將JSON字符串反序列化成JS對(duì)象,stringify方法可以將JS對(duì)象序列化成JSON字符串,借助這兩個(gè)方法,也可以實(shí)現(xiàn)對(duì)象的深拷貝。

//例1
var source = { name:"source", child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
target.name = "target"; //改變target的name屬性
console.log(source.name); //source 
console.log(target.name); //target
target.child.name = "target child"; //改變target的child 
console.log(source.child.name); //child 
console.log(target.child.name); //target child
//例2
var source = { name:function(){console.log(1);}, child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
//例3
var source = { name:function(){console.log(1);}, child:new RegExp("e") }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
console.log(target.child); //Object {}

這種方法使用較為簡(jiǎn)單,可以滿足基本的深拷貝需求,而且能夠處理JSON格式能表示的所有數(shù)據(jù)類型,但是對(duì)于正則表達(dá)式類型、函數(shù)類型等無(wú)法進(jìn)行深拷貝(而且會(huì)直接丟失相應(yīng)的值)。還有一點(diǎn)不好的地方是它會(huì)拋棄對(duì)象的constructor。也就是深拷貝之后,不管這個(gè)對(duì)象原來的構(gòu)造函數(shù)是什么,在深拷貝之后都會(huì)變成Object。同時(shí)如果對(duì)象中存在循環(huán)引用的情況也無(wú)法正確處理。

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

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

jQuery.extend = jQuery.fn.extend = function() { //給jQuery對(duì)象和jQuery原型對(duì)象都添加了extend擴(kuò)展方法
var options, name, src, copy, copyIsArray, clone,
 target = arguments[0] || {},
 i = 1,
 length = arguments.length,
 deep = false;
 //以上其中的變量:options是一個(gè)緩存變量,用來緩存arguments[i],name是用來接收將要被擴(kuò)展對(duì)象的key,src改變之前target對(duì)象上每個(gè)key對(duì)應(yīng)的value。
 //copy傳入對(duì)象上每個(gè)key對(duì)應(yīng)的value,copyIsArray判定copy是否為一個(gè)數(shù)組,clone深拷貝中用來臨時(shí)存對(duì)象或數(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ù)列表長(zhǎng)度等于i的時(shí)候,擴(kuò)展jQuery對(duì)象自身。
if ( length === i ) {
 target = this;
 --i;
}

for ( ; i < length; i++ ) {
 if ( (options = arguments[ i ]) != null ) {
  // 擴(kuò)展基礎(chǔ)對(duì)象
  for ( name in options ) {
   src = target[ name ];
   copy = options[ name ];

   // 防止永無(wú)止境的循環(huán),這里舉個(gè)例子,如var i = {};i.a = i;$.extend(true,{},i);如果沒有這個(gè)判斷變成死循環(huán)了
   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存在且是對(duì)象的話就讓clone副本等于src否則等于空數(shù)組。
    }

    // 遞歸拷貝
    target[ name ] = jQuery.extend( deep, clone, copy );

   } else if ( copy !== undefined ) {
    target[ name ] = copy;// 若原對(duì)象存在name屬性,則直接覆蓋掉;若不存在,則創(chuàng)建新的屬性。
   }
  }
 }
}

// 返回修改的對(duì)象
return target;
};

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

var a={"name":"aaa"};
var b={"name":"bbb"};
a.child=b;
b.parent=a;
$.extend(true,{},a);//直接報(bào)了棧溢出。Uncaught RangeError: Maximum call stack size exceeded

5、自己動(dòng)手實(shí)現(xiàn)一個(gè)拷貝方法

var $ = (function(){
 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 $;
})();//類型判斷

function copy(obj,deep){ 
 if(obj === null || typeof obj !== "object"){ 
  return obj; 
 }      
 var name, target = $.isArray(obj) ? [] : {}, value; 
 for(name in obj){ 
  value = obj[name]; 
  if(value === obj) {
  continue;
  }
  if(deep && ($.isArray(value) || $.isObject(value))){
  target[name] = copy(value,deep);
  }else{
  target[name] = value;
  } 
 } 
 return target;
}

看完上述內(nèi)容,你們對(duì)javaScript中淺拷貝與深拷貝的區(qū)別是什么有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。


當(dāng)前標(biāo)題:javaScript中淺拷貝與深拷貝的區(qū)別是什么
當(dāng)前網(wǎng)址:http://weahome.cn/article/posgii.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部