JavaScript | 數(shù)據(jù)類型,常量以及變量
這應該是JavaScript系列教程第三期,這期準備講一下數(shù)據(jù)類型,常量以及變量的定義。
任何的編程語言都有自己的數(shù)據(jù)類型與數(shù)據(jù)結(jié)構,那么JavaScipt也有自己的數(shù)據(jù)類型,可以將其分為基本數(shù)據(jù)類型與引用數(shù)據(jù)類型!基本數(shù)據(jù)類型指的是簡單的數(shù)據(jù)段,引用數(shù)據(jù)類型指的是有多個值構成的對象。當我們把變量賦值給一個變量時,解析器首先要確認的就是這個值是基本類型值還是引用類型值。
在JavaScipt 中,基本類型(基本數(shù)值、基本數(shù)據(jù)類型)是一種既非對象也無方法或?qū)傩缘臄?shù)據(jù)。有 7 種原始數(shù)據(jù)類型:
基本數(shù)據(jù)類型是保存在棧中的,存取的速度比較快。
引用數(shù)據(jù)類型我們通常統(tǒng)稱為Object類型,大致上分為一下5種:
引用數(shù)據(jù)類型是保存在堆當中的,這樣說可能不準確,準確的說法應該是引用數(shù)據(jù)類型的對象保存在了堆當中。
將堆和棧進行一下對比:
我們定義一個基本數(shù)據(jù)類型在棧中,應該是以下的情況。
上面的栗子就是定義了
const?a?=?1const?b?=?2const?c?=?3const?d?=?4
以上看起來是挺簡單的一對一的形式儲存的。
我們同樣來定義一下引用數(shù)據(jù)類型:
const?e?=?new?Object()const?f?=?ee.name?=?'orange'
以上代碼的存儲形式應該如下:
解釋一下上面圖片,左邊是一個棧,定義了一個引用數(shù)據(jù)類型,名稱叫做e,然后e在堆中開辟了一個空間,有了一個地址,所以棧中的值就是這個空間的地址,然后又定義了一個引用數(shù)據(jù)類型,叫做f,把e賦值給f,這個時候值也是指向了這個空間的地址。最后給這個空間加了一個值,name:'orange'。最后就是e和f其實是一個東西了。
如果你沒有聽清楚,沒搞明白,我來給你簡單翻譯一下!
假如你有一個空地,這個空地就是棧,然后這個空地上面來了a,b,c,d,e,f這幾個人(也就是名稱),然后呢a.b,c,d這四個人都是本地人,就在這個空地上修了個房間(也就是值),分別放了1,2,3,4。但是呢,e,f他不是本地人,人家有自己房子,跑到你的地方來了,他也修了東西,但是只是一個門,這個地址(也就是值)是他家(也就是堆),剛好f和e是一家人,所以就用了e的門,也通向了這個家(堆)。
不知道以上的解釋清楚了沒,在不清楚的話,私信我,我去做個動畫給你描述清楚!?。?!
在代碼中,我們是怎么判斷數(shù)據(jù)類型的,數(shù)據(jù)類型怎么轉(zhuǎn)化呢?
我們有很多方法可以用來判斷。
typeof 基本只能判斷出基本數(shù)據(jù)類型,引用類型除了function外,都是 object 。
const?typeOf?=?()?=>?{????//?基本類型????console.log(typeof(1));?//number????console.log(typeof('1'));?//string????console.log(typeof(null));?//object????console.log(typeof(false));?//boolean????console.log(typeof(undefined));?//undefined????console.log(typeof(Symbol()));?//symbol????console.log(typeof(NaN));?//number????//?引用類型????console.log(typeof?{});?//object????console.log(typeof?[]);?//object????console.log(typeof?Error('1'));?//object????function?A()?{}????console.log(typeof?A);?//function}typeOf()
instanceof 返回是true或false,只能對引用數(shù)據(jù)類型進行判斷。
const?instanceOf?=?()?=>?{????//?基本類型????console.log(1?instanceof?Number);?//false????console.log("1"?instanceof?String);?//false????console.log(true?instanceof?Boolean);?//false????console.log(null?instanceof?Object);?//false????console.log(undefined?instanceof?Object);?//false????console.log(Symbol()?instanceof?Symbol);?//false????//?引用類型????console.log({}?instanceof?Object);?//true????console.log([]?instanceof?Array);?//true????console.log(Error('1')?instanceof?Error);?//true????function?A()?{}????console.log(A?instanceof?Function);?//true}instanceOf()
Object.prototype.toString.call() 返回是一個[object xxx]的字符串,可以通過slice(8, -1)的方式來獲取完整的數(shù)據(jù)類型。
const?stringCall?=?()?=>?{????//?基本類型????console.log(Object.prototype.toString.call(1));?//[object?Number]????console.log(Object.prototype.toString.call(1).slice(8,?-1))?//Number????console.log(Object.prototype.toString.call('1').slice(8,?-1))?//String????console.log(Object.prototype.toString.call(true).slice(8,?-1))?//Boolean????console.log(Object.prototype.toString.call(null).slice(8,?-1))?//Null????console.log(Object.prototype.toString.call(undefined).slice(8,?-1))?//Undefined????console.log(Object.prototype.toString.call(NaN).slice(8,?-1))?//Number????console.log(Object.prototype.toString.call(Symbol()).slice(8,?-1))?//Symbol????//?引用數(shù)據(jù)類型????console.log(Object.prototype.toString.call({}).slice(8,?-1))?//Object????console.log(Object.prototype.toString.call([]).slice(8,?-1))?//Array????console.log(Object.prototype.toString.call(Error('1')).slice(8,?-1))?//Error????function?A()?{}????console.log(Object.prototype.toString.call(A).slice(8,?-1))?//Function}stringCall()
即可以判斷基本數(shù)據(jù)類型,也可以判斷引用數(shù)據(jù)類型,由于null和undefined沒有constructor,所以判斷不了,同時由于constructor可以改變,所以此方法如果改寫了constructor,就不準確了。
const?constructorName?=?()?=>?{????//?基本數(shù)據(jù)類型????console.log((1).constructor.name);?//Number????console.log('1'.constructor.name);?//String????//?console.log((null).constructor.name);?//報錯?Cannot?read?properties?of?null?(reading?'constructor')????//?console.log((undefined).constructor.name);?//報錯?Cannot?read?properties?of?undefined?(reading?'constructor')????console.log((true).constructor.name);?//Boolean????console.log((NaN).constructor.name);?//Number????console.log((Symbol()).constructor.name);?//Symbol????//?引用數(shù)據(jù)類型????console.log(({}).constructor.name);?//Object????console.log(([]).constructor.name);?//Array????console.log((Error('1')).constructor.name);?//Error????function?A()?{}????console.log((A).constructor.name);?//Function}constructorName()
可以判斷基本數(shù)據(jù)類型,也可以判斷引用數(shù)據(jù)類型,由于null和undefined沒有constructor,所以判斷不了。因為constructor.toString().indexOf()也是用到了constructor,所以如果該寫了constructor后,就不準確了。
const?toStringIndexOf?=?()?=>?{????//?基本數(shù)據(jù)類型????console.log((1).constructor.toString());?//function?Number()?{?[native?code]?}????console.log((1).constructor.toString().indexOf('Number')?>?-1)?//true????console.log(('1').constructor.toString().indexOf('String')?>?-1)?//true????//?console.log((null).constructor.toString().indexOf('Null')?>?-1)?//報錯,Cannot?read?properties?of?null?(reading?'constructor')????//?console.log((undefined).constructor.toString().indexOf('Undefined')?>?-1)?//報錯,?Cannot?read?properties?of?undefined?(reading?'constructor')????console.log((Symbol()).constructor.toString().indexOf('Symbol')?>?-1)?//true????console.log((true).constructor.toString().indexOf('Boolean')?>?-1)?//true????console.log((NaN).constructor.toString().indexOf('Number')?>?-1)?//true????//?引用數(shù)據(jù)類型????console.log(({}).constructor.toString().indexOf('Object')?>?-1)?//true????console.log(([]).constructor.toString().indexOf('Array')?>?-1)?//true????console.log((Error('1')).constructor.toString().indexOf('Error')?>?-1)?//true????function?A()?{}????console.log((A).constructor.toString().indexOf('Function')?>?-1)?//true}toStringIndexOf()
改寫constructor
const?num?=?new?Number(1)console.log((num).constructor.name);?//Numberconsole.log((num).constructor.toString().indexOf('Number')?>?-1)?//truefunction?A()?{}num.constructor?=?Aconsole.log((A).constructor.name);?//Functionconsole.log((A).constructor.toString().indexOf('Function')?>?-1)?//true
這里說的類型轉(zhuǎn)換是字符串和數(shù)值之間的轉(zhuǎn)換。
toString(),18.toString()
String(),String(18)
拼接,18+''
以上三種辦法都可以將數(shù)值類型轉(zhuǎn)化為字符串類型。
Number(),Number('18')
parseInt(),parseInt('18')
parseFloat(),parseFloat('18')
+或-,-'18'或者+'18'
以上四種方法都可以將字符串轉(zhuǎn)化為字符串。
我們在定義的時候,分為常量與變量,一般可以使用var,const,let來定義。
es5的時候我們都是用var來定義常量與變量。但是很容易造成變量提升或者變量的全局污染。所以我們現(xiàn)在很少使用這個了。
es6的方法,使用const來定義常量與變量。比如定義基礎數(shù)據(jù)類型的常量,const a = 1,這個就是定義一個a 的常量,不可以更改。這里的不可以更改指的是基礎數(shù)據(jù)類型不能更改,引用數(shù)據(jù)類型不能更改其類型,但是可以更改其值。
const?a?=?1const?b?=?{?name:'orange',?age:18}//?修改aa?=?2?//這個肯定要報錯的b.age?=?20?//這個可以更改
這也是es6的語法,使用let定義變量,不管是基礎數(shù)據(jù)類型還是引用數(shù)據(jù)類型都可以,同時可以更改。
let?a?=?1let?b?=?{??name:'orange',??age:18}//?修改aa?=?2b.age?=?20b?=?3