好程式設計師web前端培訓分享JavaScript相關知識

好程式設計師發表於2020-07-22

  好程式設計師web 前端培訓分享 JavaScript 相關知識 今天跟大家分享的是關於JavaScript 相關知識。正在從事 web 前端工作的小夥伴們來一起看看吧,希望能夠對大家有所幫助。

   ( )JS 中基本型別和引用型別

   JavaScript 的變數中包含兩種型別的值:基本型別值和引用型別值,在記憶體中的表現形式在於:前者是儲存在棧中的一些簡單的資料段,後者則是儲存在堆記憶體中的一個物件。

   •基本型別值

   JavaScript 中基本資料型別有 String Number Undefined Null Boolean ,在 ES6 中,又定義了一種新的基本資料型別 Symbol ,所以一共有 6 種。

   基本型別是按值訪問的,從一個變數複製基本型別的值到另一個變數後,這兩個變數的值是完全獨立的,即使一個變數改變了也不會影響到第二個變數。

   let str1 = ' 你好 ';

   let str2 = str1;

   str2 = 'hello word'console.log(str2);//'hello word'

   console.log(str1); //' 你好 '

   •引用型別值

   引用型別值是引用型別的例項,它是儲存在堆記憶體中的一個物件,引用型別是一種資料結構,最常用的是Object,Array,Function 型別,此外還有 Date,RegExp,Error 等。

   ES6 中提供了 Set,Map2 種新的資料結構。

   ( )JS 中如何複製引用型別的

   •基本型別和引用型別賦值的差異化

   舉個例子:在下面程式碼中,只修改了obj1 中的 name 屬性,卻同時改變了 ob1 obj2 中的 name 屬性。

   let obj1 = {'name': ' 小明 '};

   let obj2 = obj1;obj2.name = ' 小蘭 ';

   console.log(obj1); // {'name': ' 小明 '}

   console.log(obj2); // {'name': ' 小明 '}

   當變數複製引用型別值的時候,同樣和基本型別值一樣會將變數的值複製到新變數上,不同的是對於變數的值,它是一個指標,指向儲存在堆記憶體中的物件。

   因為,在JS 中,堆記憶體中的物件無法直接訪問,必須要訪問這個物件在堆記憶體中的地址,然後再按照這個地址去獲得這個物件中的值。

   ( ) 淺複製

   JS 中,如果屬性是基本型別,複製的就是基本型別的值 ; 如果屬性是引用型別,複製的就是記憶體地址 ; 所以如果其中一個物件改變了這個地址,就會影響到另一個物件。

   下面是JavaScript 提供的淺複製方法:

   Object.assign

   ES6 中複製物件的方法,接受的第一個引數是複製的目標,剩下的引數是複製的源物件 ;

   語法:Object.assign(target, ...sources)

   let p = { 'name': 'hello word',};

   let copyP = {};

   Object.assign(copyP, p);

   console.log(copyP);console.log(p);

   Object.assign 是一個淺複製,它只是在根屬性 ( 物件的第一層級 ) 建立了一個新的物件,但是如果屬性的值是物件的話,只會複製一份相同的記憶體地址。

   擴充套件運算子

   利用擴充套件運算子可以在構造字面量物件時,進行克隆或者屬性複製。語法如下:

   let cloneObj = { ...obj };

   let obj = {'name': ' 星期一 ' 'college': [' 星期二 ' ' 星期三 ' ' 星期四 ']}let obj2 = {...obj};

   obj.name=' 不休息 ';//{'name': ' 不休息 ' 'college': [' 星期二 ' ' 星期三 ' ' 星期四 ']}console.log(obj);//{'name': ' 星期一 ' 'college': [' 星期二 ' ' 星期三 ' ' 星期四 ']}

   console.log(obj2);

   obj.college.push('Go');//{'name': ' 不休息 ' 'college': [' 星期二 ' ' 星期三 ' ' 星期四 ']}

   console.log(obj); //{'name': ' 不休息 ' 'college': [' 星期二 ' ' 星期三 ' ' 星期四 ']}

   console.log(obj2);

   擴充套件運算子和Object.assign() 存在同樣的問題,對於值是物件的屬性無法完全複製成兩個不同物件 ;

   但是如果屬性都是基本型別的值的話,使用擴充套件運算子更加簡潔。

   ( ) 深複製

   淺複製只在根屬性上在堆記憶體中建立了一個新的的物件,複製了基本型別的值,但是複雜資料型別也就是物件則是複製相同的地址。

   而深複製則是將一個物件從記憶體中完整的複製一份出來,從堆記憶體中開闢一個新的區域存放新物件,且修改新物件不會影響原物件。

   JSON.stringify

   JSON.stringify() 是目前開發過程中最常用的深複製方式,原理是把一個物件序列化成為一個 JSON 字串,將物件的內容轉換成字串的形式再儲存在記憶體中,再用 JSON.parse() 反序列化將 JSON 字串變成一個新的物件。

   舉個例子:

   let obj = { name: ' 少帥 ', age: 18, friends: [' 阿大 ', ' 阿二 '], goodF: { name: ' 水果 ', age: 19, address: ' 上海 ', pets: [{name: ' 西瓜 '}, {name: ' 蘋果 '}]}, bir: new Date()};

   let newObj = JSON.parse(JSON.stringify(obj));

   obj.goodF.pets[0].name = ' 桔子 ';

   console.log(newObj);console.log(obj);

   使用JSON.stringify 實現深複製有幾點要注意:

   1) 複製的物件的值中如果有函式 ,undefined,symbol ,經過 JSON.stringify() 序列化後的 JSON 字串中這個鍵值對會消失 ;

   2) 無法複製不可列舉的屬性,無法複製物件的原型鏈

   3) 複製 Date 引用型別會變成字串

   4) 複製 RegExp 引用型別會變成空物件

   5) 物件中含有 NaN Infinity -Infinity ,則序列化的結果會變成 null

   遞迴實現深複製

   具體實現如下:

   /** * 輔助函式 , 判定是否是物件 * @param obj * @returns {boolean} */

   function isObj(obj) { return obj instanceof Object;}

   /** * 深複製 fromObj 面的所有屬性 / , toObj 物件裡面 * @param fromObj 複製物件 * @param toObj 目標物件 */

   function deepCopyObj2NewObj(fromObj, toObj) {

   for (let key in fromObj) {

   if(fromObj.hasOwnProperty(key)){

   let fromValue = fromObj[key]; // 如果是值型別,那麼就直接複製賦值

   if (!isObj(fromValue)) {

   toObj[key] = fromValue;

   } else { // 如果是引用型別,那麼就再呼叫一次這個方法, // 去內部複製這個物件的所有屬性 // fromValue 是什麼型別 , 建立一個該型別的空物件

   let tmpObj = new fromValue.constructor;

   // console.log(tmpObj); // debugger;

   deepCopyObj2NewObj(fromValue, tmpObj);

   toObj[key] = tmpObj;

   }

   }

   }}

   ( ) 總結

   1) 在日常開發中一般並不需要複製很多特殊的引用型別,深複製物件使用 JSON.stringify 是最直接和簡單的方法。

   2) 實現一個完整的深複製是非常複雜的 , 需要考慮到很多邊界情況。對於特殊的引用型別有複製需求的話,建議藉助第三方完整的庫 , 例如 lodash.js


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2706174/,如需轉載,請註明出處,否則將追究法律責任。

相關文章