一、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