1. 程式人生 > 實用技巧 >JS的資料型別你真的懂了嗎

JS的資料型別你真的懂了嗎

一、JS資料型別分類

  1.基本資料型別

    (1)Number 數字

    (2)String 字串

    (3)Boolean 布林值

    (4)null 空物件指標

    (5)undefined 為定義

    (6)symbol(es6新增,表示獨一無二的值)

    (7)bigint(ES10新增,表示比number資料型別支援的範圍更大的整數值)

    注意:NaN是Number中的一種特殊數值,不是一種資料型別

  2.引用資料型別

    object,array和function都是object的子型別

  3.基本資料型別和引用資料型別的區別

    (1)宣告變數時記憶體分配不一樣

      基本資料型別:在棧中,因為佔據空間是固定的,可以將他們存在較小的記憶體中-棧中,這樣便於迅速查詢變數的值

      引用資料型別:存在堆中,棧中儲存的變數,只是用來查詢堆中的引用地址。

      理由:引用值的大小會改變,所以不能把它放在棧中,否則會降低變數查尋的速度。相反,放在變數的棧空間中的值是該物件儲存在堆中的地址。地址的大小是固定的,所以把它儲存在棧中對變數效能無任何負面影響

    (2)不同的記憶體分配帶來不同的訪問機制

      在javascript中是不允許直接訪問儲存在堆記憶體中的物件的,所以在訪問一個物件時,首先得到的是這個物件在堆記憶體中的地址,然後再按照這個地址去獲得這個物件中的值,這就是傳說中的按引用訪問。 而基本資料型別的值則是可以直接訪問到的。

    (3)複製變數時的不同

      基本資料型別:在將一個儲存著原始值的變數複製給另一個變數時,會將原始值的副本賦值給新變數,此後這兩個變數是完全獨立的,他們只是擁有相同的value而已。

      引用資料型別:在將一個儲存著物件記憶體地址的變數複製給另一個變數時,會把這個記憶體地址賦值給新變數, 也就是說這兩個變數都指向了堆記憶體中的同一個物件,他們中任何一個作出的改變都會反映在另一個身上。 (這裡要理解的一點就是,複製物件時並不會在堆記憶體中新生成一個一模一樣的物件,只是多了一個儲存指向這個物件指標的變數罷了)

    (4)引數傳遞的不同

       基本資料型別:只是把變數的值傳遞給引數,之後這個引數和變數互不影響

      引用資料型別:傳遞是物件在堆記憶體裡面的地址,他們指向同一個物件。

二、資料型別的判斷方式

  1.typeof

    typeof返回一個表示資料型別的字串,返回結果包括:number、boolean、string、symbol、object、undefined、function等7種資料型別,但不能判斷null、array等

  2.instanceof

    instanceof 是用來判斷a是否為b的例項,表示式為:a instanceof b,如果a是b的例項,則返回true,否則返回false。instanceof 運運算元用來測試一個物件在其原型鏈中是否存在一個建構函式的 prototype 屬性,但它不能檢測null和 undefined   

  3.constructor

    constructor作用和instanceof非常相似。但constructor檢測 object與instanceof不一樣,還可以處理基本資料型別的檢測。不過函式的 constructor 是不穩定的,這個主要體現在把類的原型進行重寫,在重寫的過程中很有可能出現把之前 的constructor給覆蓋了,這樣檢測出來的結果就是不準確的。

  4.object.prototype.tostring.call() :是最準確最常用的方式。

程式碼示例:

Object.prototype.toString.call();               // [object String]

Object.prototype.toString.call(1);              // [object Number]

Object.prototype.toString.call(true);           // [object Boolean]

Object.prototype.toString.call(undefined);      // [object Undefined]

Object.prototype.toString.call(null);           // [object Null]

Object.prototype.toString.call(new Function()); // [object Function]

Object.prototype.toString.call(new Date());     // [object Date]

Object.prototype.toString.call([]);             // [object Array]

Object.prototype.toString.call(new RegExp());   // [object RegExp]

Object.prototype.toString.call(new Error());    // [object Error]

三、JS資料型別轉換

  1.強制轉換

    (1)toPrimitive(obj,type)轉換為原始值

      toPrimitive對基本資料型別不發生轉換處理,只針對引用資料型別,作用是將引用資料型別轉換為基本資料型別。ToPrimitive運運算元有兩個引數,第一個引數obj是需要轉換的物件,第二個引數type是期望轉換為的原始資料型別(可選)

      對於引數2 type的說明:

        type=String,首先呼叫obj的toString方法,如果為原始值則return,否則呼叫obj的valueOf方法,如果為原始值則return,否則丟擲TypeError異常

        type=Number,首先呼叫obj的valueOf方法,如果為原始值則return,否則呼叫obj的toString方法,如果為原始值則return,否則丟擲TypeError異常

        type引數為空,如果obj是Date物件,則type=String,其它情況把type=Number處理

    (2)toString

      返回一個表示該物件的字串,每個物件都有toString方法,當物件被表示為文字值時或者當以期望字串的方式引用物件時,該方法自動呼叫

var obj={}
console.log(obj.toString())//[object Object] var arr=[1,"111"]
console.log(arr.valueOf())//陣列本身
console.log(arr.toString())//1,111
console.log(arr.toLocaleString())//1,111

     (3)valueOf

      Javascript呼叫valueOf方法來把物件轉換成原始型別的值(數值、字串、布林值)。某些情況會被自動呼叫

      array 陣列的元素被轉換為字串,這些字串由逗號分隔,連線在一起。其操作與 array.tostring 和 array.join 方法相同。

      boolean boolean 值。

      date 儲存的時間是從 1970 年 1 月 1 日午夜開始計的毫秒數 utc。

      function 函式本身。

      number 數字值。

      object 返回"[object object]",前一個object標記基礎型別,後一個object標記子型別

      string 字串值。

      math 和 error 物件沒有 valueof 方法。

var str="我是string";
var num=5;
var date=new Date();
var obj={
name:"cc",
age:16
}
console.log(str.valueOf())//我是string
console.log(num.valueOf())//5
console.log(date.valueOf())//1574577999115
console.log(obj.valueOf())//{name: "cc", age:16}

    (4)Number()

       null==》0、undefined==》NaN、true==》1、false==》0 

      字串轉換時遵循數字常量規則,如果有不是數字的內容則轉換失敗返回 NaN

Number(null);       //0
Number(undefined); //NaN
Number(true); //1
Number(false); //0
Number('1'); //1
Number('a'); //NaN

    (5)String()

      null、undefined、true、false都加上引號

      數字轉換遵循通用規則,溢位將以指數形式或者無窮大(Infinity)

String(null)                 //"null"
String(undefined) //"undefined"
String(true) //"true"
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(1E+400) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,[3,4]],['a']) // '1,2,3,4,a'
String(function (){return 0}) //function({return 0})

    (6)Boolean

      undefined、null、0、+0、-0、NaN、空字串轉換為false,其餘都為true

Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true

  2.隱式轉換

 

四、資料型別面試題

  1.js中typeOf資料型別分別輸出什麼

console.log(typeof 1);//Number
console.log(typeof NaN);//Number
console.log(typeof '1');//String
console.log(typeof null);//Object
console.log(typeof undefined);//undefined
console.log(typeof true);//Boolean
console.log(typeof false);//Boolean
console.log(typeof {});//Object
console.log(typeof []);//Object
console.log(typeof function(){var a=1});//function

    特別注意,null、空物件、空陣列的結果都是Object,function的結果就是function

  2.null和undefined有什麼區別

    一句話概括:undefined是未定義的,null是定義了但是為空。如果對他倆進行==判斷,結果為true。用===判斷,結果為false

  3.==和===有什麼區別

    簡單來說: == 代表相同, ===代表嚴格相同

    理解: 當進行雙等號比較時候: 先檢查兩個運算元資料型別,如果相同, 則進行===比較, 如果不同, 則願意為你進行一次型別轉換, 轉換成相同型別後再進行比較(如何轉換看上面的圖片), 而===比較時, 如果型別不同,直接就是false.

    運算元1 == 運算元2, 運算元1 === 運算元2

    比較過程:

      雙等號==:

        (1)如果兩個值型別相同,再進行三個等號(===)的比較

        (2)如果兩個值型別不同,也有可能相等,需根據以下規則進行型別轉換在比較:

            1)如果一個是null,一個是undefined,那麼相等

            2)如果一個是字串,一個是數值,把字串轉換成數值之後再進行比較

      三等號===:

        (1)如果型別不同,就一定不相等

        (2)如果兩個都是數值,並且是同一個值,那麼相等;如果其中至少一個是NaN,那麼不相等。(判斷一個值是否是NaN,只能使用isNaN( ) 來判斷)

         (3)如果兩個都是字串,每個位置的字元都一樣,那麼相等,否則不相等。

         (4)如果兩個值都是true,或是false,那麼相等

        (5)如果兩個值都引用同一個物件或是函式,那麼相等,否則不相等

        (6)如果兩個值都是null,或是undefined,那麼相等

  4.請說出以下程式碼的執行結果和理由(區分算術運運算元和字串拼接)

console.log(1 + 'true')//‘1true’
console.log(1 + true)//2
console.log(1 + undefined)//NaN
console.log(1 + null)//1

    console.log(1 + 'true')//‘1true’【字串拼接,會把其他資料型別轉為字串然後拼接】
    console.log(1 + true)//2 【加法運算會把其他資料型別轉為數字再進行加法運算】
  5.請說出以下程式碼的執行結果和理由(關係運算子)

console.log('2'>10)//false
console.log('2'>'10')//true
console.log('abc'>'a')//false
console.log('abc'>'aad')//true
console.log(NaN == NaN )//false
console.log(undefined == null )//true

  console.log('2'>10)//false 【關係運算子只有一邊是字串時,會把其他資料型別轉為數字,然後比較】

  console.log('2'>'10')//true 【如果兩邊都是字串,同事轉成字元對應的編碼值進行比較】

  console.log('abc'>'a')//false 【如果是多個字元,從左到右依次比較,先比較‘a’和‘b’,如果不等直接出結果】ps:大小比較的是字元的ASCII碼值

  console.log('abc'>'aad')//true【如果相等,則比較第二個字元,根據相等於否得出結果】

  console.log(NaN == NaN )//false 【NaN和任何資料比較都是false】

  console.log(undefined == null )//true【undefined和null使用==判定相等,與自身判定也相等】

  6.請說出以下程式碼的執行結果和理由(複雜資料型別)

console.log([1,2] == '1,2')//true
console.log([1,2].valueOf())// [1,2]
console.log([1,2].toString())// 1,2 var a={}
console.log(a == '[object Object]')//true
console.log(a.valueOf().toString())//[object Object]

  當物件和字串比較時先呼叫valueOf()再呼叫toString方法,然後再進行比較

  下面看一道進階題:

var a=???
if(a == 1 && a == 2 && a == 3){
console.log(3)
}
如何填寫a,使得函式打印出3

  小爐:乍一看,a怎麼可能等於1、2、3呢,這題有問題叭!

  前端大佬:非也非也,要知道,在資料型別的比較中,有的可以執行valueOf、toString方法的,突破口就在這裡,那麼我們重寫他的方法,就可以實現改變a值。不多說了,直接上程式碼:(其他方案傳送門)

var a={
i:0,
valueOf:function(){
return ++a.i
}
}
if(a == 1 && a == 2 && a == 3){
console.log(3)
}

  7.請說出以下程式碼的執行結果和理由(邏輯非隱式轉換和關係運算子隱式轉換)

程式碼(1)
console.log([]==0)//true
console.log(![]==0)//true

程式碼(2)
console.log([]==![])//true
console.log([]==[])//false

程式碼(3)
console.log({}==!{})//false
console.log({}=={})//false

  首先,你要知道,關係運算子將其他資料型別轉成數字,邏輯非:將其他資料型別使用boolean轉為布林型別。

  程式碼(1)

  [].valueOf.toString()得到空串,空串轉為數字是0,所以判斷[]==0是true
  邏輯非優先順序高於關係運算子,所以![]先是空陣列轉為布林true,然後取反是false。0轉為布林也是false所以判斷![]==0是true

  程式碼(2)

  邏輯非優先順序高於關係運算子,所以![]先是空陣列轉為布林true,然後取反是false。然後是空陣列轉變得到空串,字串和布林進行==比較,將他們二者轉為數字進行比較。所以都為0,判定最後結果為true。

  console.log([]==[])//false 因為是引用資料型別,棧中存的是地址,所以不相等

  程式碼(3)

  邏輯非優先順序高於關係運算子,先執行{}.valueOf.toString()得到'[object Object]',對他取反為false,然後將他和空物件都數字化,然後得到0==0,判定他們相等,所以結果為true。

  console.log({}=={})//false 因為是引用資料型別,棧中存的是地址,所以不相等

五、總結

  1.資料型別分為基本資料型別(7種,ES10新增bigint)和引用資料型別(Object和他的子型別array、function)

  2.有四種判斷方式,typeOf、instanceOf、constructor、object.prototype.tostring.call()

  3.資料型別有強制轉換和隱式轉換(面試題考點)

  4.總體來說,需要記的東西很多。多練多做題才更熟悉

參考檔案:https://www.cnblogs.com/c2016c/articles/9328725.html

      https://blog.csdn.net/itcast_cn/article/details/82887895