溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

深入淺析JS中的淺層克隆與深度克隆

發布時間:2020-11-05 16:56:47 來源:億速云 閱讀:218 作者:Leah 欄目:開發技術

深入淺析JS中的淺層克隆與深度克???針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

1 相關知識點

  1. 淺克隆就是將棧內存中的引用復制一份,賦給一個新的變量,本質上兩個指向堆內存中的同一地址,內容也相同,其中一個變化另一個內容也會變化。
       深克隆就是創建一個新的空對象,開辟一塊內存,然后將原對象中的數據全部復制過去,完全切斷兩個對象間的聯系。
  2. 區別:淺克隆和深克隆最大的區別就是對引用值的處理了,即淺克隆之后你改我也改,深克隆之后你改我不改。(PS:原始值的處理一樣)
  3. 原始值(棧數據stack):Number,Boolean(false/true),String,undefined,null
  4. 引用值(堆數據heap):Array,Object,function ··· Date,RegExp
       2 淺層克隆

在淺層克隆中,原始值的克隆沒問題,只是值的拷貝,不會出現你改我改的問題。但是引用值的克隆,就會出現你改我也改的問題,因為淺層克隆的是地址,即指向的是同一空間。

2.1 淺克隆函數

function clone(origin, target) {
  var target = target || {}; 
  //容錯,即防止用戶不傳遞目標參數。若用戶傳遞了參數就用,若沒傳則拿一個空對象當目標
  for (var prop in origin) {
    target[prop] = origin[prop];
  }
  return target;
}

2.2 運用實例

function clone(origin, target) {
  var target = target || {}; 
  for (var prop in origin) {
    target[prop] = origin[prop];
  }
  return target;
}

var obj = {
  name: 'abc',
  age: '18',
  sex: 'male',
  card: ['a', 'b', 'c'],
  book: {
    name: 'ccc',
    sbook: {
      name: 'aaa'
    }
  }
};
var newobj = {};

clone(obj, newobj);

運行代碼如下:

深入淺析JS中的淺層克隆與深度克隆

3 深度克隆

進行深度克隆之后,對于引用值的克隆的問題就會和原始值一樣我改你不改,因為在深度克隆中雖然是相同的東西,但是指向不同的空間。即深度克隆之后,值各自獨立,互不影響。

3.1 深克隆步驟分析

需要進行深度克隆的對象如下:

var obj = {
  name: 'abc', // 原始值
  age: '18', // 原始值
  sex: 'male',// 原始值
  card: ['a', 'b', 'c'], // 引用值
  book: { // 引用值
    name: 'ccc', // 原始值
    sbook: { // 引用值
      name: 'aaa'// 原始值
    }
  }
};

var obj1 = {};

(1)首先需要遍歷要克隆的對象

方法:for (var prop in origin){···}

for (var prop in origin) {
	···
}

(2)依次判斷是不是原始值

方法:typeof() ,即若為原始值,就直接拷貝;若為引用值(typeof(···)返回的值是object),則進行遞歸操作。需要注意是的typeof(null) == 'object',所以得排除這一個情況。

if (origin[prop] !== "null" && typeof(origin[prop]) == 'object') {
	···
	// 遞歸
} else {
  target[prop] = origin[prop];
}

(3)判斷是數組還是對象

方法:toString(推薦), constructor,instanceof (后兩個會涉及到父子域的小問題,雖然遇到的可能不是很大)

var toStr = Object.prototype.toString,
  arrStr = "[object Array]";
if (toStr.call(origin[prop]) == arrStr) {
	··· // 數組
} else {
	··· // 對象
}

(4)建立相應的數組或對象

方法:建立一個新的同名空數組 / 對象,并將原始對象中的 數組或對象 當成一個新的原始對象,再次將其中的數據拷貝到目標對象的 同名空數組 / 對象 里面。即遞歸開始拷貝數組或對象里面的數據,并遞歸執行第(1)步。遞歸完成之后,再依次進行下一個數據的克隆。

var toStr = Object.prototype.toString,
  arrStr = "[object Array]";
if (toStr.call(origin[prop]) == arrStr) {
	target[prop] = [];
} else {
	target[prop] = {};
}
newobj = {
  name: 'abc',
  age: '18',
  sex: 'male',
  card: [] 
  // 建立一個新的同名空數組,并把obj的card數據當成一個原始對象,再次拷貝到obj1的card里面
  // 即 遞歸開始拷貝數組或對象里面的數據,遞歸執行第(1)步
  // 執行完數組card拷貝之后,開始同理拷貝下一個對象book···
}

3.2 深克隆函數

function deepClone(origin, target) {
  var target = target || {},
    toStr = Object.prototype.toString,
    arrStr = "[object Array]";
  for (var prop in origin) {
    if (origin.hasOwnProperty(prop)) {
      if (origin[prop] !== "null" && typeof(origin[prop]) == 'object') {
        if (toStr.call(origin[prop]) == arrStr) {
          target[prop] = [];
        } else {
          target[prop] = {};
        }
        deepClone(origin[prop], target[prop]);

      } else {
        target[prop] = origin[prop];
      }
    }
  }
  return target;
}

使用三目運算符簡化后的代碼如下:

// 使用三目運算符簡化后
function deepClone(origin, target) {
  var target = (target || {}),
    toStr = Object.prototype.toString,
    arrStr = "[object Array]";
  for (var prop in origin) {
    if (origin.hasOwnProperty(prop)) {
      if (origin[prop] !== "null" && typeof (origin[prop]) == 'object') {
        target[prop] = toStr.call(origin[prop]) == arrStr ? [] : {};
        deepClone(origin[prop], target[prop]);
      } else {
        target[prop] = origin[prop];
      }
    }
  }
  return target;
}

3.3 運用實例

// 使用三目運算符簡化后
function deepClone(origin, target) {
  var target = (target || {}),
    toStr = Object.prototype.toString,
    arrStr = "[object Array]";
  for (var prop in origin) {
    if (origin.hasOwnProperty(prop)) {
      if (origin[prop] !== "null" && typeof (origin[prop]) == 'object') {
        target[prop] = toStr.call(origin[prop]) == arrStr ? [] : {};
        deepClone(origin[prop], target[prop]);
      } else {
        target[prop] = origin[prop];
      }
    }
  }
  return target;
}

運行代碼如下:

深入淺析JS中的淺層克隆與深度克隆

3.4 hasOwnProperty

hasOwnProperty() 方法會返回一個布爾值,指示對象自身屬性中是否具有指定的屬性(即是否有指定的鍵)。

語法:obj.hasOwnProperty(prop)
參數:要檢測的屬性的字符串形式表示的名稱,或者Symbol。
返回值:用來判斷某個對象是否含有指定的屬性的布爾值。
描述:所有繼承了Object的對象都會繼承到hasOwnProperty方法。這個方法可以用來檢測一個對象是否含有特定的自身屬性;和in運算符不同,該方法會忽略掉那些從原型鏈上繼承到的屬性。
用法:
a. 使用hasOwnProperty方法判斷屬性是否存在
b. 區別自身屬性與繼承屬性
c. 遍歷一個對象的所有自身屬性
d. 使用hasOwnProperty作為屬性名
具體知識點請參考 Object.prototype.hasOwnProperty()

若對象里面編寫了原型屬性,但遍歷的時候并不想讓其顯示出來,就可以使用對象名.hasOwnProperty(屬性名) 來判斷是否是自身屬性,若是自己的則返回值為true,若不是自身原型屬性則返回值為false。實例如下:

var obj = {
	name: 'ABC',
	age: '18',
	sex: 'male',
	__proto__: {
		heart: 'happy'
	}
}
for (var prop in obj) {
	// 配套使用,起到一個過濾的作用,不把原型鏈上的數據弄出來
	if (obj.hasOwnProperty(prop)) {
		console.log(obj[prop]);// ABC 18 male
	}
}

關于深入淺析JS中的淺層克隆與深度克隆問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女