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.總體來說,需要記的東西很多。多練多做題才更熟悉
參考文檔://www.cnblogs.com/c2016c/articles/9328725.html
//blog.csdn.net/itcast_cn/article/details/82887895