記得剛學(xué)習(xí)js的時(shí)候,在變量的賦值上經(jīng)常會(huì)出現(xiàn)一些自認(rèn)為是莫名奇妙的bug,自己找了半天也找不出問(wèn)題~
當(dāng)然js的數(shù)據(jù)類(lèi)型轉(zhuǎn)化也是讓我頭疼不已~ 明明上一秒還是小明,下一秒就變成了小紅,經(jīng)常是讓人摸不著頭腦.最為一個(gè)有自知之明的前端小菜鳥(niǎo),還是有必要花時(shí)間來(lái)整理一下這些知識(shí)點(diǎn)的 ,把關(guān)于數(shù)據(jù)類(lèi)型的知識(shí)點(diǎn)給整理了一下~做個(gè)小小的分享
以下是本文的提綱
數(shù)據(jù)類(lèi)型
基本類(lèi)型
引用類(lèi)型
不同數(shù)據(jù)類(lèi)型的賦值區(qū)別
不同數(shù)據(jù)類(lèi)型作為參數(shù)傳遞的區(qū)別
數(shù)據(jù)類(lèi)型隱式轉(zhuǎn)化
基本運(yùn)算
1.字符串與數(shù)組相比
2.==與 = ==
3.布爾類(lèi)型與其他類(lèi)型
4.null和undefined
5.引用類(lèi)型運(yùn)算
數(shù)據(jù)類(lèi)型判斷
typeof
Object.prototype.toString.call()
到底什么是數(shù)據(jù)類(lèi)型?
就是計(jì)算機(jī)里面有各種數(shù)據(jù)值,不同的數(shù)據(jù)值的處理方式和儲(chǔ)蓄方式都不同,我們?yōu)檫@些值分好了類(lèi)別,統(tǒng)稱(chēng)為 數(shù)據(jù)類(lèi)型
通俗點(diǎn)來(lái)說(shuō),就是計(jì)算機(jī)也需要對(duì)人說(shuō)人話,對(duì)鬼說(shuō)鬼話~
但是...現(xiàn)實(shí)中總是那么殘酷,來(lái)看幾段代碼先
//數(shù)據(jù)類(lèi)型間的賦值
var a =1 ;
var b =a ;
function num (c){
c = 999;
}
num(a);
console.log(a)//1
console.log(b)//1
?
var obj = {
a:1
}
var obj2 = obj;
console.log(obj2); //1
?
obj2.a= 10;
console.log(obj)
------------------------------------------------------
console.log(1 + 'abc') /1abc
?
var obj = {
width: '100'
};
?
obj.width + 20 // "10020"
----------------------------------------------------
?
var a = [1,2];
?
var b = [3,4];
?
console.log(a+b); //1,23,4
?
----------------------------------------------------------
true + 0 // 1</pre>
那為什么會(huì)出現(xiàn)這樣的情況呢,明明上一秒還是字符串,下一秒就變成了number
數(shù)值與字符串相加,結(jié)果變成了字符串的拼接
數(shù)組間的相加雖然不常見(jiàn),但是結(jié)果也是讓人匪夷所思
為了弄清楚這些問(wèn)題.我不得不查閱了大量資料,以及做一些必要的測(cè)試來(lái)搞懂他,首先還是要對(duì)js中的數(shù)據(jù)類(lèi)型要有個(gè)大致的了解~
js中的數(shù)據(jù)類(lèi)型總共分為2個(gè)大類(lèi), 基本類(lèi)型,對(duì)象類(lèi)型,也可以叫做值類(lèi)型和引用類(lèi)型
先來(lái)看看基本類(lèi)型,常見(jiàn)的基本類(lèi)型總共有5種
js中提供了一種檢測(cè)當(dāng)前變量的數(shù)據(jù)類(lèi)型的方法碟嘴,也就是typeof關(guān)鍵字,我們先來(lái)試試看
注意:[ typeof對(duì)于基本類(lèi)型挟伙,除了 null 都可以顯示正確的類(lèi)型 ]
Number
String
Boolean
Undefined
Null
var a = 'abc';
var b = 1;
var c =true;
var d = undefined;
var e = null;
?
var f = [];
var g = {};
?
function h () {
console.log(1)
}
console.log(typeof(a)) //string
console.log(typeof(b)) //number
console.log(typeof(c)) //boolean
console.log(typeof(d)) //undefined
console.log(typeof(e)) //object</pre>
為什么null打印出來(lái)是object呢 , 原因在于這是js的一個(gè)語(yǔ)言bug,null 本身是基本類(lèi)型涕蚤。
原理是這樣的烤低,不同的對(duì)象在底層都表示為二進(jìn)制,在 JavaScript 中二進(jìn)制前三位都為 0 的話會(huì)被判斷為 object 類(lèi)型,null 的二進(jìn)制表示是全 0,自然前三位也是 0跛璧,所以執(zhí)行 typeof 時(shí)會(huì)返回“object”。
引用類(lèi)型:
數(shù)組
function
Obj
var f = [];
var g = {};
?
function h () {
console.log(1)
}
?
console.log(typeof(f)) //object
console.log(typeof(g)) //object
console.log(typeof(h)) //object</pre>
在這里其實(shí)可以發(fā)現(xiàn),typeof只可以檢測(cè)基本的數(shù)據(jù)類(lèi)型,而引用類(lèi)型的檢測(cè)不出具體的數(shù)據(jù)類(lèi)型的,關(guān)于檢測(cè)數(shù)據(jù)類(lèi)型,我們?cè)诤竺嬖倏磣
基本類(lèi)型和引用類(lèi)型之間的區(qū)別
我們先來(lái)看第一個(gè)問(wèn)題:把boj賦值一份給obj2,當(dāng)改變了obj2中的屬性值,obj的屬性值也發(fā)生了改變,
不同數(shù)據(jù)類(lèi)型間賦值區(qū)別
簡(jiǎn)單數(shù)據(jù)類(lèi)型是存在內(nèi)存中的棧中的,而引用類(lèi)型的數(shù)據(jù)是存在內(nèi)存中的堆中的,但是變量的聲明都是在棧上
賦值只是把棧中的內(nèi)存地址給另外一個(gè)變量,基本數(shù)據(jù)類(lèi)型就等于把值復(fù)制給了另一個(gè),引用類(lèi)型就等于把我的內(nèi)存地址賦值給另外一個(gè)變量,而他們都指向同一個(gè)堆中的數(shù)據(jù)
而引用類(lèi)型數(shù)據(jù)存儲(chǔ)在堆中,棧中的地址指向堆,obj1改變堆中的數(shù)據(jù),obj又跟她指向同一個(gè).
//數(shù)據(jù)類(lèi)型間的賦值
var a =1 ;
var b =a ;
console.log(a)//1
console.log(b)//1
?
?
var obj = {
a:1
}
var obj1 = obj;
console.log(obj2); //1
?
obj1.a= 10;
console.log(obj)</pre>
一張圖簡(jiǎn)單的來(lái)理解
不同數(shù)據(jù)類(lèi)型間傳參區(qū)別
var a =1 ;
function num (c){
c = 999;
}
num(a);
console.log(c)//999
?
?
var obj = {
a:10
}
?
function changen(obj1){
obj1.a=30;
}
changen(obj);
console.log(obj.a) //30</pre>
數(shù)據(jù)類(lèi)型隱式轉(zhuǎn)化
字符串和數(shù)字比較新啼,字符串會(huì)被轉(zhuǎn)換數(shù)字
布爾值和其他類(lèi)型比較追城,會(huì)被轉(zhuǎn)換成數(shù)字
運(yùn)算符
基本數(shù)據(jù)類(lèi)型
我們發(fā)現(xiàn),js在對(duì)不同數(shù)據(jù)類(lèi)型做運(yùn)算的時(shí)候,會(huì)把不同類(lèi)型的變量進(jìn)行轉(zhuǎn)變,比如 1 + '1' = ‘11’,簡(jiǎn)單數(shù)據(jù)類(lèi)型的隱式轉(zhuǎn)化常見(jiàn)的有以下幾種
字符串加數(shù)字,數(shù)字就會(huì)轉(zhuǎn)成字符串(上面已經(jīng)寫(xiě)了)
數(shù)字減字符串,字符串轉(zhuǎn)成數(shù)字 (1 - '1' //0)
console.log(1-'1') // 0
- 如果字符串不是純數(shù)字就會(huì)轉(zhuǎn)成NaN燥撞。字符串減數(shù)字也一樣, 乘座柱,除,大于物舒,小于跟減的轉(zhuǎn)換也是一樣色洞。
console.log(1-'1a') //NAN</pre>
==與===
== 允許在相等比較中進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換,而== = 不允許,如果兩個(gè)值的類(lèi)型不同冠胯,我們就需要考慮有沒(méi)有強(qiáng)制類(lèi)型轉(zhuǎn)換的必要火诸,有就用= =,沒(méi)有就用===荠察,不用在乎性能。
//字符串和數(shù)字之間的相等比較哨啃,將字符串轉(zhuǎn)換為數(shù)字再進(jìn)行比較
var a =1;;
var b ='1';
a==b //true
a===b //false</pre>
其他類(lèi)型與布爾類(lèi)型相比
//先將布爾類(lèi)型轉(zhuǎn)為數(shù)字
true //1
false //0
var a = true;
var b = '999';
a == b //false</pre>
null和undefined比較
console.log(null == undefined) //trun
console.log(null === undefined) //false</pre>
引用類(lèi)型
var a = [1,2];
var b = [3,4];
console.log(a+b); //1,23,4</pre>
要解決這個(gè)疑問(wèn),先要了解以下es5的規(guī)范
ES5 規(guī)范11.6.1 節(jié)拼坎,如果某個(gè)操作數(shù)是字符串或者能夠通過(guò)以下步驟轉(zhuǎn)換為字符串的話,+ 將進(jìn)行拼接操作媚污。如果其中一個(gè)操作數(shù)是對(duì)象(包括數(shù)組),則首先對(duì)其調(diào)用ToPrimitive 抽象操作(規(guī)范9.1 節(jié))廷雅,該抽象操作再調(diào)用[[DefaultValue]](規(guī)范8.12.8節(jié))耗美,以數(shù)字作為上下文
如果加其中的一個(gè)操作數(shù)是字符串(或者通過(guò)此規(guī)范能得到字符串),則進(jìn)行字符串拼接航缀,否則執(zhí)行數(shù)字加法
ToPrimitive會(huì)做以下3件事:
1.先計(jì)算obj.valueOf(),,如果結(jié)果為原始值,則返回此結(jié)果 (obj值的是引用的數(shù)據(jù)類(lèi)型)
2.否則.計(jì)算obj.toString(),如果結(jié)果是原始值,則返回此結(jié)果
3.否則,拋出異常
var arr = [1,2];
console.log(arr.valueOf()); // [1,2]
console.log(arr.toString()); // 1,2</pre>
數(shù)據(jù)類(lèi)型檢測(cè)
typeof(檢查基本數(shù)據(jù)類(lèi)型)
typeof對(duì)于基本數(shù)據(jù)類(lèi)型判斷是沒(méi)有問(wèn)題的商架,但是遇到引用數(shù)據(jù)類(lèi)型(如:Array,obj,function)是不起作用的,輸出的都是object,那個(gè)這個(gè)時(shí)候檢查引用數(shù)據(jù)類(lèi)型就要用到下面這個(gè)方法了
var f = [];
var g = {};
?
function h () {
console.log(1)
}
?
console.log(typeof(f)) //object
console.log(typeof(g)) //object
console.log(typeof(h)) //object</pre>
Object.prototype.toString.call() (檢查引用數(shù)據(jù)類(lèi)型)
var f = [];
var g = {};
function h () {
console.log(1)
}
console.log(Object.prototype.toString.call(f)); //[object Array]
console.log(Object.prototype.toString.call(g)); //[object Object]
console.log(Object.prototype.toString.call(h)); //[object Function]</pre>