成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Javascript數據類型知多少?

開發 前端
正如你所知道的,數據類型是作為js的入門知識點,在整個js的學習過程中也是尤為重要的。數據類型看起來簡單,但是圍繞著其衍生的邊界數據類型判斷問題、深拷貝淺拷貝問題對于新手而言是難以理解的。

[[438470]]

正如你所知道的,數據類型是作為js的入門知識點,在整個js的學習過程中也是尤為重要的。數據類型看起來簡單,但是圍繞著其衍生的邊界數據類型判斷問題、深拷貝淺拷貝問題對于新手而言是難以理解的。

一、數據類型

JavaScript 是一種弱類型或者說動態類型,這就意味著你不需要提前聲明變量的類型,在程序運行的過程中,類型會被自動確定。這就意味著你可以使用同一個變量保存不同類型的數據.

js內存分為棧內存(stack)和堆內存(heap)

  • 棧內存:是一種特殊的線性表,它具有后進先出的特性,存放基本類型。
  • 堆內存:存放引用類型(在棧內存中存一個基本類型值保存對象在堆內存中的地址,用于引用這個對象)。

數據類型根據存儲方式分為兩類:

  • 基本數據類型(簡單數據類型、原始數據類型):值存儲在棧內存中,被引用或拷貝時,會創建一個完全相等的變量。占用空間小、大小固定,通過按值來訪問,屬于被頻繁使用的數據。
  • 引用數據類型(復雜數據類型):地址存儲在棧內存中,值存在了堆內存中,多個引用會指向同一個地址。占據空間大、占用內存不固定。如果存儲在棧中,將會影響程序運行的性能;引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址后從堆中獲得實體。

根據上面的標準劃分數據類型,常見的有:

  • 基本數據類型:String、Number、Boolean、Undefined、Null、Symbol、BigInt
  • 復雜數據類型:Object、Array、Date、Function、RegExp等

未命名文件 (1).png

二、數據類型的檢測

通常的數據類型的檢測有三種方法:

  • typeof
  • instanceof

2.1 typeof

使用typeof進行基礎數據類型(null除外)檢測,但是對于引用數據類型,除了function外,其它的均無法進行判斷。

  1. typeof "yichuan"; //"string" 
  2. typeof 18; //"number" 
  3. typeof undefined; //undefined 
  4. typeof true; //boolean 
  5. typeof Symbol(); //"symbol" 
  6. typeof null; //"object" 
  7. typeof []; //"object" 
  8. typeof {}; //"object" 
  9. typeof console; //"object" 
  10. typeof console.log; //"function" 

2.2 instanceof

使用instanceof是通過原型鏈進行查找,可以準確地判斷復雜引用數據類型,但是不能準確判斷基礎數據類型。

  1. let Fun = Function(){}; 
  2. let fun = new Fun(); 
  3. fun instanceof Fun;//true 
  4.  
  5. let str = new String("yichuan"); 
  6. str instanceof String;//true 
  7.  
  8. let str = "yichuan"
  9. str instanceof String;//false 

2.3 Object.prototype.toString.call()

Object.prototype.toString方法返回對象的類型字符串,因此可用來判斷一個值的類型。因為實例對象有可能會自定義toString方法,會覆蓋Object.prototype.toString,所以在使用時,最好加上call。所有的數據類型都可以使用此方法進行檢測,且非常精準。

  1. Object.prototype.toString.call("yichuan");//["object String"
  2. Object.prototype.toString.call(18);//["object Number"
  3. Object.prototype.toString.call(true);//["object Boolean"
  4. Object.prototype.toString.call(null);//["object Null"
  5. Object.prototype.toString.call(new Symbol());//["object Symbol"
  6. Object.prototype.toString.call({});//["object Object"
  7. Object.prototype.toString.call([]);//["object Array"
  8. Object.prototype.toString.call(/123/g);//["object RegExp"
  9. Object.prototype.toString.call(function(){});//["object Function"
  10. Object.prototype.toString.call(new Date());//["object Date"
  11. Object.prototype.toString.call(document);//["object HTMLDocument"
  12. Object.prototype.toString.call(window);//["object Window"

我們可以看到此輸出的結果都是["object Xxxx"]首字母大寫。

2.4 通用的數據類型判斷方法

  1. function getType(obj){ 
  2.  //先判斷輸入的數據判斷返回結果是否為object 
  3.   if(typeof obj !== "object"){ 
  4.    return typeof obj; 
  5.   } 
  6.   // 對于typeof返回object的,再進行具體的判斷,使用正則返回結果,切記正則中間有個空格哦 
  7.   return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/,"$1"); 

切記:

  • 使用typeof返回的類型是小寫
  • 使用toString返回的類型是大寫
  1. getType("yichuna");//"string" 
  2. getType(18);//"number" 
  3. getType(true);//"boolean" 
  4. getType(undefined);//"undefined" 
  5. getType();//"undefined" 
  6. getType(null);//"Null" 
  7. getType({});//"Object" 
  8. getType([]);//"Array" 
  9. getType(function(){});//"Function" 
  10. getType(new Date());//"Date" 
  11. getType(/123/g);//"RegExp" 

三、數據類型轉換

3.1 強制類型轉換

常見的強制類型轉換方法有:

  • Number()
  • String()
  • Boolean()
  • parseInt()
  • parseFloat()
  • toString()

3.2 Number()方法的強制轉換規則

  • 布爾值 true和false分別被轉換為1和0
  • 數字 返回本身
  • null 返回0
  • undefined 返回NaN
  • 字符串
    • 如果字符串中只包含數字,則將其轉換為十進制
    • 如果字符串中只包含有有效的浮點格式,將其轉換為浮點數值
    • 如果是空字符串,將其轉換為0
    • 如果不是以上格式的字符串,則均返回NaN
    • Symbol 拋出異常

3.3 Boolean()方法的強制轉換規則

undefined、null、false、""、0(包括+0、-0)、NaN轉換出來都是false,其余類型轉換都是true。特別注意:Boolean({})轉換為true

3.4 隱式類型轉換==

  • 如果類型相同,無需進行類型轉換
  • 如果其中一個操作值為null或undefined,那么另一個操作符必須是null或undefined才會返回true,否則均返回false
  • 如果其中一個值是Symbol類型,那么返回false
  • 如果其中一個操作知為Boolean,那么轉為number
  • 兩個操作值均為string和number類型,那么將字符串轉為number
  • 如果一個操作值為object,且另一個為string、number或symbol,就會把object轉為原始數據類型判斷

小試牛刀:

  1. null == undefined; //true 
  2. null == 0;//false 
  3. "" == null;//false 
  4. "" == 0;//true 會轉為number類型再進行判斷 
  5. "123" == 123;//true 
  6. 0 == false;//true 
  7. 1 == true;//true 

3.5 隱式類型轉換+

"+"號操作符,不僅可以用于數字相加,還可以用于字符串拼接。

  • 如果其中一個是字符串,另外一個是number、undefined、null或boolean,則調用toString()方法進行字符串拼接
  • 如果是純字符串、數組、正則等,則默認調用對象的轉換方法會存在優先級,然后進行拼接
  • 如果字符串和bigInt進行相加,會先將bigInt轉為字符串
  • 如果number類型與undefined相加,則得到NaN
  1. 1 + 2;//3 
  2. 1 + "2";//"12" 
  3.  
  4. "1" + undefined;//"1undefined" 
  5. "1" + null;//"1null" 
  6. "1" + true;//"1true" 
  7. "1"  + 1n;//"11" 字符串和bigInt進行相加,會先將bigInt轉為字符串 
  8.  
  9. 1 + undefined;//NaN undefined會先轉為NaN 
  10. 1 + null;//1 null轉為0 
  11. 1 + true;//2 
  12. 1 + 1n;//Error 

3.6 object的轉換規則

  • 如果部署了Symbol.toPrimitive方法,優先調用再返回
  • 調用valueOf(),如果轉換為基礎類型則返回
  • 調用toString(),如果轉換為基礎數據類型則返回
  • 如果都沒有返回基礎數據類型,則會報錯

四、深拷貝和淺拷貝

在js的編程中經常需要進行數據進行復制,那么什么時候使用深拷貝、什么時候使用淺拷貝呢,是開發過程中需要思考的?如何提升自己手寫js的能力,以及對一些邊界情況的深入思考能力呢?

有兩個重要問題:

  • 拷貝一個很多嵌套的對象要如何實現呢?
  • 深拷貝寫成什么程度才能讓面試官滿意呢?

4.1 淺拷貝的原理和實現

自己創建一個新的對象,來接受要重新復制或引用的對象值。

  • 如果對象屬性是基本數據類型,復制的就是基本數據類型的值給新對象;
  • 如果對象屬性是引用數據類型,賦值的則是內存中的地址,如果其中一個對象改變了這個內存中的地址,肯定會影響另外一個對象

4.1.1 Object.assign

Object.assign是es6中object的一個方法,該方法可以用于js對象的合并等多個用途,其中一個用途就是可以進行淺拷貝。

  1. Object.assign(target,...sources);//target目標對象,sources待拷貝的對象 

注意:

  • Object.assign不會拷貝對象的繼承屬性
  • Object.assign不會拷貝對象的不可枚舉屬性

例如:

  1. let obj = {}; 
  2. let obj1 = { 
  3.  name:"yichuan"
  4.   scores:{ 
  5.    math:100, 
  6.     Chinese:100 
  7.   } 
  8. }; 
  9.  
  10. Object.assign(obj,obj1); 
  11. console.log(obj);//{name:"yichuan",scores:{math:100,Chinese:100}} 

改變目標對象的值:我們可以看到下面改變了目標對象的值,會引起待拷貝對象的值的改變。

  1. let obj = {}; 
  2. let obj1 = { 
  3.  name:"yichuan"
  4.   scores:{ 
  5.    math:100, 
  6.     Chinese:100 
  7.   } 
  8. }; 
  9. Object.assign(obj,obj1); 
  10.  
  11. console.log(obj);//{name:"yichuan",scores:{math:100,Chinese:90}} 
  12. obj.scores.Chinese = 10; 
  13. console.log(obj);//{name:"yichuan",scores:{math:100,Chinese:90}} 
  14. console.log(obj1);//{name:"yichuan",scores:{math:100,Chinese:90}} 

不可拷貝不可枚舉屬性

  1. let obj1 = { 
  2.  user:{ 
  3.    name:"yichuan"
  4.     age:18 
  5.   }, 
  6.   idCard:Symbol(1) 
  7. }; 
  8.  
  9. Object.defineProperty(obj1,"innumerable",{ 
  10.   value:"不可枚舉屬性"
  11.   enumerable:false 
  12. }); 
  13.  
  14. let obj2 = {}; 
  15. Object.assign(obj2,obj1); 
  16. obj1.user.name = "onechuan"
  17.  
  18. console.log("obj1",obj1);//{user: {…}, idCard: Symbol(1), innumerable: '不可枚舉屬性'
  19. console.log("obj2",obj2);//{user: {…}, idCard: Symbol(1)} 我們可以看到并沒有innumerable屬性 

4.1.2 展開運算符

  1. /* 對象的拷貝 */ 
  2. let obj1 = { 
  3.  user:{ 
  4.    name:"yichuan"
  5.     age:18 
  6.   }, 
  7.   school:"實驗小學" 
  8. }; 
  9.  
  10. let obj2 = {...obj1}; 
  11. obj2.school = "五道口男子技校"
  12. console.log(obj1);//{school: "實驗小學",user: {name'yichuan', age: 18}} 
  13. obj2.user.age = 19; 
  14. console.log(obj2);//{school: "實驗小學",user: {name'yichuan', age: 19}} 
  15.  
  16. /* 數組的拷貝 */ 
  17. let arr = ["red","green","blue"]; 
  18. let newArr = [...arr]; 
  19. console.log(arr);//['red''green''blue'
  20. console.log(newArr);//['red''green''blue'

4.1.3 concat拷貝數組

數組的concat方法其實也是淺拷貝

  1. let arr = ["red","green","blue"]; 
  2. let newArr = arr.concat(); 
  3. newArr[1] = "black"
  4. console.log(arr);//["red","green","blue"]; 
  5. console.log(newArr);//["red","black","blue"]; 

4.1.4 slice拷貝數組

slice方法僅針對數組類型,arr.slice(begin,end);

  1. let arr = ["red","green","blue"]; 
  2. let newArr = arr.slice(); 
  3. newArr[1] = "black"
  4. console.log(arr);//["red","green","blue"]; 
  5. console.log(newArr);//["red","black","blue"]; 

4.1.5 手寫淺拷貝

  • 對基本數據類型進行最基本的拷貝
  • 對引用數據類型開辟新的存儲,并且拷貝一層對象屬性
  1. function shallowClone(target){ 
  2.  //先要判斷是否為對象數據類型 
  3.   if(typeof target === "object" && target !== null){ 
  4.     //判斷輸入的是object類型還是數組類型 
  5.    const cloneTarget = Array.isArray(target) ?[]:{}; 
  6.     //遍歷目標對象元素 
  7.     for(let prop in target){ 
  8.      //判斷cloneTarget對象上是否有此屬性,沒有進行拷貝 
  9.       if(!cloneTarget.hasOwnProperty(prop)){ 
  10.        cloneTarget[prop] = target[prop] 
  11.       } 
  12.     } 
  13.     return cloneTarget; 
  14.   } 
  15.   return target; 

4.2 深拷貝的原理和實現

前面我們知道淺拷貝只是創建了一個新的對象,復制了原有對象的基本類型的值。對于復雜引用數據類型,其在堆內存中完全開辟了一塊內存地址,并將原有對象完全復制過來存放。

深拷貝就是將一個對象從內存中完整地拷貝出來給目標對象,并在堆內存中開辟新的空間進行存儲新對象的值,且新對象的值改變不會影響原對象,也就是實現了二者的隔離。

4.2.1 JSON.stringify()

其實在實際開發過程使用最簡單的深拷貝就是使用JSON.stringify()配合JSON.parse()。但其實是有缺陷的,不影響簡單使用。注意:

  1. let obj1 = { 
  2.  user:{ 
  3.    name:"yichuan"
  4.     age:18 
  5.   }, 
  6.   school:"實驗小學" 
  7. }; 
  8. let obj2 = JSON.parse(JSON.stringify(obj1)); 
  9. console.log(obj1);//{school: "實驗小學",user: {name'yichuan', age: 18}} 
  10. console.log(obj2);//{school: "實驗小學",user: {name'yichuan', age: 18}} 
  11. obj2.school = "門頭溝學員"
  12. obj2.user.age = 19; 
  13. console.log(obj1);//{school: "實驗小學",user: {name'yichuan', age: 18}} 
  14. console.log(obj2);//{school: "門頭溝學院",user: {name'yichuan', age: 19}} 

4.2.2 簡易手寫深拷貝

作為簡易版手寫深拷貝,只能完成基礎的拷貝功能,也存在一些缺陷:

  • 不能拷貝不可枚舉的屬性以及symbol類型
  • 只能針對普通的引用類型的值做遞歸復制
  • 對象的屬性里面成環,即循環引用沒有得到妥善解決
  1. function deepClone(obj){ 
  2.  const cloneObj = {}; 
  3.   //遍歷對象鍵名 
  4.   for(let key in obj){ 
  5.     //判斷是否為對象類型 
  6.     if(typeof obj[key]==="object"){ 
  7.       //是對象就再次調用函數進行遞歸拷貝 
  8.       cloneObj[key] = deepClone(obj[key]); 
  9.     }else
  10.       //是基本數據類型的話,就直接進行復制值 
  11.       cloneObj[key] = obj[key]; 
  12.     } 
  13.      
  14.   } 
  15.   return cloneObj; 
  16.  
  17. const obj1 = { 
  18.  user:{ 
  19.    name:"yichuan"
  20.     age:18 
  21.   }, 
  22.   school:"實驗小學" 
  23.  
  24. let obj2 = deepClone(obj1); 
  25. obj1.user.age = 19; 
  26. console.log(obj2);//{school: "實驗小學",user: {name'yichuan', age: 18}} 

4.2.3 優化版手寫深拷貝

對于上面簡易版的深拷貝,很顯然面試官是不買賬的,為此我們針對遞歸進行升級處理。

  • 針對能夠遍歷對象的不可枚舉屬性以及Symbol類型,我們可以使用Reflect.ownKeys方法
  • 當參數為Date、RegExp類型,則直接生成一個新的實例返回
  • 利用Object的getOwnPropertyDescriptors方法可以獲得對象的所有屬性,以及對應的特性,順便結合Object.create()方法創建新對象,并繼承傳入原對象的原型鏈
  • 利用WeakMap類型作為Hash表,因為WeakMap是弱引用類型,可以有效防止內存泄漏,作為檢測循環引用有很大的幫助。如果存在循環,則引用直接返回WeakMap存儲的值
  1. const isComplexDataType = (obj) => (typeof obj === 'object' || typeof obj === 'function') && obj !== null
  2.  
  3. function deepClone(obj, hash = new WeakMap()) { 
  4.   //判斷是否為日期類型 
  5.   if (obj.constructor === Datereturn new Date(obj); 
  6.   //判斷是否正則對象 
  7.   if (obj.constructor === RegExp) return new RegExp(obj); 
  8.   //如果循環引用了,就使用weakMap進行解決 
  9.   if (hash.has(obj)) return hash.get(obj); 
  10.  
  11.   const allDesc = Object.getOwnPropertyDescriptors(obj); 
  12.   //遍歷傳入參數所有鍵的特性 
  13.   const cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc); 
  14.   //繼承原型鏈 
  15.   hash.set(obj, cloneObj); 
  16.   for (const key of Reflect.ownKeys(obj)) { 
  17.     cloneObj[key] = isComplexDataType(obj[key]) && typeof obj[key] !== 'function' ? deepClone(obj[key]) : obj[key]; 
  18.   } 
  19.   return cloneObj; 
  20.  
  21. const obj1 = { 
  22.   num: 2021, 
  23.   str: 'jue'
  24.   bool: true
  25.   nul: null
  26.   arr: ['ref''green''blue'], 
  27.   date: new Date(0), 
  28.   reg: new RegExp('/123/g'), 
  29.   user: { 
  30.     name'yichuan'
  31.     age: 18 
  32.   }, 
  33.   school: '實驗小學' 
  34. }; 
  35. const obj2 = deepClone(obj1); 
  36. obj1.user.age = 19; 
  37. console.log(obj2);//{arr: ['ref''green''blue'],bool: true,date: Thu Jan 01 1970 08:00:00 GMT+0800 (中國標準時間) ,nul: null,num: 2021,reg: /\/123\/g/,school: "實驗小學",str: "jue",user: {name'yichuan', age: 18}} 

5參考學習

《如何寫出一個驚艷面試官的深拷貝?》

《JavaScript基本數據類型和引用數據類型》

《Javascript核心原理精講》

6寫在最后

 

其實在實際開發和使用過程中,很多人對于深拷貝的細節問題理解并不是很透徹,如果能夠更深層次的研究細節,你就會發現此部分內容對于了解更深層次js的底層原理有所幫助。這篇文章是作為對數據類型、數據類型的檢測、數據類型強制和隱藏轉換、深淺拷貝的簡要總結,希望對大家有所幫助。

 

責任編輯:武曉燕 來源: 前端萬有引力
相關推薦

2021-12-04 11:17:32

Javascript繼承編程

2021-12-10 07:47:30

Javascript異步編程

2016-08-18 14:13:55

JavaScript基本數據引用數據

2021-02-25 07:08:30

JavaScript 前端面試題

2021-12-11 18:59:35

JavascriptJSON應用

2010-10-08 15:11:28

JavaScript數

2021-12-07 08:01:33

Javascript 垃圾回收機制前端

2021-12-05 08:27:56

Javascript 高階函數前端

2012-02-13 22:50:59

集群高可用

2024-08-06 10:07:15

2010-10-08 09:02:03

JavaScript基

2011-07-29 10:12:12

JavaScript

2021-12-06 07:15:48

Javascript作用域閉包

2010-08-16 09:15:57

2013-12-23 14:00:31

Windows 8.2Windows 8.1

2025-04-14 08:50:00

Google ADK人工智能AI

2017-07-14 10:51:37

性能優化SQL性能分析

2018-11-15 09:45:47

JavaScript數據類型變量

2022-05-18 20:01:07

K8sIP 地址云原生

2009-05-13 17:31:06

DBAOracleIT
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九色视频网站 | 国产亚洲一区二区精品 | 久久人爽爽人爽爽 | 欧美精品一区二区三区蜜桃视频 | av电影手机版 | 久视频在线| 欧美日韩黄色一级片 | 精品国产伦一区二区三区观看说明 | 国产精品18久久久久久久 | 日日夜夜精品视频 | 国产一级淫片免费视频 | www免费视频| 日韩欧美三区 | 一级少妇女片 | 成人免费视频一区二区 | 东京av男人的天堂 | 亚洲二区视频 | 91国产精品在线 | 精品国产乱码久久久久久a丨 | 国产片一区二区三区 | 亚洲网站在线观看 | 鸳鸯谱在线观看高清 | 中文精品久久 | 日韩一级一区 | 国产美女在线观看 | 九九色九九 | 精品久久影院 | 欧美一区二区三区国产精品 | 欧洲在线视频 | 中文天堂在线一区 | 中文字幕一区二区三区日韩精品 | 亚洲综合二区 | 久草视频2 | 午夜在线 | 精品国产伦一区二区三区观看体验 | 紧缚调教一区二区三区视频 | 狠狠操狠狠干 | 国产美女精品 | 国产在线不卡视频 | 可以在线观看av的网站 | 国产视频久久久久 |