JavaScript 定義了幾種數(shù)據(jù)類型? 哪些是原始類型?哪些是復雜類型?
最新的 ECMAScript 標準定義了 7 種數(shù)據(jù)類型:
原始類型
Number;數(shù)值類型;值:整數(shù)和小數(shù)。
String;字符串類型;值:字符串組成的文本。
Boolean;布爾類型;值:true、false。
Undefined;值:undefined(表示“未定義”或不存在,即由于目前沒有定義)。
Null;值null(表示無值,即此處的值就是“無”的狀態(tài))。
Symbol;值:symbol(ECMAScript 6 新定義,表示唯一值)。
復雜類型
Object;對象類型;值:各種 “ key:value ” 組成的集合。
區(qū)別
原始類型(基本類型)都是存放著一個確定的值,它們對內(nèi)存的占用大小是確定的,存放著棧內(nèi)存中。
復雜類型存放的內(nèi)容是不確定的,占用的內(nèi)存也是變化的,它的棧內(nèi)存用固定的內(nèi)存存放它在內(nèi)存中的位置,而可變化的內(nèi)容存放著堆內(nèi)存中。
基本類型變量存的是值,復雜類型的變量存的是內(nèi)存地址。
基本類型在賦值的時候拷貝值,復雜類型在賦值的時候只拷貝地址,不拷貝值。
判斷一個變量是否是數(shù)字、字符串、布爾、函數(shù)
JavaScript有三種方法,可以確定一個值到底是什么類型。
typeof運算符
instanceof運算符
Object.prototype.toString方法(以后再做介紹)
typeof 是用于返回一個值的數(shù)據(jù)類型,對于常見的幾大數(shù)據(jù)類型都可以用typeof 數(shù)據(jù)類型的方式進行判斷。
一元運算符,運算格式:
typeof xxx
返回結(jié)果是類型的字符串
數(shù)值、字符串、布爾值分別返回number、string、boolean。
typeof 123; //number
typeof '123'; //string
typeof false; //boolean
函數(shù)返回function。
function f() {};
typeof f; //function
undefined返回undefined。
typeof undefined; //undefined
除此以外,其他情況都返回object。(局限性)
typeof window; //object
typeof {}; //object
typeof []; //object
typeof null; //object
instanceof 是用于判斷某個對象是不是構(gòu)造函數(shù)的一個實例,舉例來說就是一個新聲明的變量是不是調(diào)用了構(gòu)造函數(shù)的內(nèi)置屬性或方法,區(qū)分狹義對象、數(shù)組、日期、函數(shù)等。
二元運算符
instanceof 是一個二元運算符,左邊a是被運算的值,右邊b是運算的類型。格式如下:
a instanceof b
使用instanceof的都必須是對象。所以不屬于object類型的基本類型是無法應用instanceof的,或者無法得到你想要的結(jié)果。
1 instanceof Number
//false
new Number(1) instanceof Number
//true
'string' instanceof String
//false
new String('string') instanceof String
//true
返回結(jié)果是布爾值(Boolean):true/false
所以instanceof是一個判斷,而typeof是求值
var o = {};
var a = [];
o instanceof Array; //false
a instanceof Array; //true
NaN是什么? 有什么特別之處?
NaN 是一種特殊的 Number 類型值。
通常作為沒有得到預期數(shù)值的返回值,如作為 Math 的某個方法的返回值出現(xiàn)的(例如:Math.sqrt(-1))或者嘗試將一個字符串解析成數(shù)字但失敗了的時候(例如:parseInt("blabla"))
NaN是JavaScript之中唯一不等于自身的值。
typeof NaN // "number"
NaN !== NaN // true
NaN === NaN // false
任何涉及NaN的數(shù)值操作都會返回NaN,如NaN+10返回NaN
如何把非數(shù)值轉(zhuǎn)化為數(shù)值?
在JavaScript中,有3個函數(shù)可以把非數(shù)值轉(zhuǎn)換為數(shù)值,這三個函數(shù)分別是:Number() 、parselnt() 和 parseFloat()。
第一個函數(shù),即轉(zhuǎn)型函數(shù) Nurnber() 可以用于任何數(shù)據(jù)類型,而另兩個函數(shù)則專門用于把字符串轉(zhuǎn)換成數(shù)值。這3個函數(shù)對于同樣的輸入會返回不同的結(jié)果。
Number() 函數(shù)
如果是 Boolean 值,true 和 false 將分別被轉(zhuǎn)換為 1 和0;
如果是數(shù)字值,只是簡單的傳入和返回;
如來是null 值,返回 0;
如果是 undefined,返回NaN ;
如果是字符串,遵循下列規(guī)則:
如果字符串中只包含數(shù)字,則將其轉(zhuǎn)換為十進制數(shù)值,即"1"會變成1 , "123"會變成123,而"011"會變成11(注意,前導的0被忽略了);
如果字符串中包含有效的浮點格式, 如"1.1",則將其轉(zhuǎn)換為對應的浮點數(shù)值(同樣,也會忽略前導零);
如果字符串中包含有效的十六進制格式,例如"0xf",則將其轉(zhuǎn)換為相同大小的十進制整數(shù)值;
如果字符串是空的(包含空字符) ,則將其轉(zhuǎn)換為0;
如果字符串中包含除上述格式之外的字符,則將其轉(zhuǎn)換為 NaN。
如果是對象,則調(diào)用對象的 valueOf() 方法,然后依照前面的規(guī)則轉(zhuǎn)換返回的值。如果轉(zhuǎn)換的結(jié)果是 NaN,則調(diào)用對象的 toString() 方法,然后再次依照前面的規(guī)則轉(zhuǎn)換返回的字符串值。
var num1 = Number("Hello world!"); // NaN
var num2 = Number(" "); // 0
var num3 = Numberl("000011"); // 11
var num4 = Number(true); // 1
parseInt() 函數(shù)
由于 Number() 函數(shù)在轉(zhuǎn)換字符串時比較復雜而且不夠合理,因此在處理整數(shù)的時候更常用的是 parseInt() 函數(shù)。
parselnt() 函數(shù)在轉(zhuǎn)換字符串時,更多的是看其是否符合數(shù)值模式,它會忽略字符串前面的空格,直至找到第一個非空格字符;如果第一個字符不是數(shù)字字符或者負號,parseInt() 就會返回 NaN;也就是說,用parselnt() 轉(zhuǎn)換空字符時會返回 NaN(Nurnber() 對空字符返回 0); 如果第一個字符是數(shù)字字符,parselnt() 會繼續(xù)解析第二個字符,直到解析完所有后續(xù)字符或者遇到了一個非數(shù)字字符。例如,"1234blue"會被轉(zhuǎn)換為1234 ,因為"blue"會被完全忽略;類似地,"'22.5"會被轉(zhuǎn)換為22 ,因為小數(shù)點并不是有效的數(shù)字字符。
如果字符串中的第一個字符是數(shù)字字符,parselnt() 也能夠識別出各種整數(shù)格式(即前面討論的十進制、八進制和十六進制數(shù)) 。也就是說,如果字符以"0x"開頭且后跟數(shù)字字符,就會將其當作一個十六進制整數(shù);如果字符串以"0"開頭且后跟數(shù)字字符,則會將其當作一個八迸制數(shù)來解析。
ES5不再允許將帶有前綴0的數(shù)字視為八進制數(shù),而是要求忽略這個0。但是,為了保證兼容性,大部分瀏覽器并沒有部署這一條規(guī)定。
var num1 = parselnt ("1234blue") ; // 1234
var num2 = parselnt (" ") ; // NaN
var num3 = parselnt ("0xA") ; // 10(十六進制數(shù))
var num4 = parseInt(22.5); // 22
var num5 = parselnt ("070") ; // 56(八進制數(shù))
var num6 = parselnt("70"); //70(十進制數(shù))
var num7 = parselnt ("0xf") ; // 15(十六進制數(shù))
如果知道被解析的是十六進制格式的字符串,那么指定基數(shù)16 作為第二個參數(shù),可以保證得到正確的結(jié)果,例如:
var num = parselnt("0xAF", 16); //175
實際上,如果指定了16 作為第二個參數(shù),字符串可以不帶前面的"0x",如下所示:
var num1 = parseInt( 'AF' , 16); //175
var num2 = parselnt ("AF") ; // NaN
指定基數(shù)會影響到轉(zhuǎn)換的輸出結(jié)果。例如:
var num1 = parselnt ("10", 2); // 2(按照二進制解析)
var num2 = parseInt("10", 8); // 8(按照八進制解析)
var num3 = parselnt("10", 10); // 10(按照十進制解析)
var num4 = parselnt("10", 16); // 16(按照十六進制解析)
parseFloat() 函數(shù)
與 parseInt () 函數(shù)類似,parseFloat () 也是從第一個字符(位置0)開始解析每個字符。而且也是一直解析到字符串末尾,或者解析到遇見一個無效的浮點數(shù)字字符為止。也就是說,字符串中的第一個小數(shù)點是有效的,而第二個小數(shù)點就是無效的了,因此它后面的字符串將被忽略。舉例來說,"22.34.5"將會被轉(zhuǎn)換為22.34 。
除了第一個小數(shù)點有效之外, parseFloat () 與 parselnt() 的第二個區(qū)別在于它始終都會忽略前導的零。parseFloat() 可以識別前面討論過的所有浮點數(shù)值格式,也包括十迸制整數(shù)格式,但十六進制格式的字符串則始終會被轉(zhuǎn)換成0。由于 parseFloat() 只解析十進制值,因此它沒有用第二個參數(shù)指定基數(shù)的用法。最后還要注意一點:如果字符串包含的是一個可解析為整數(shù)的數(shù)(沒有小數(shù)點,或者小數(shù)點后都是零),parseFloat() 會返回整數(shù)。以下是使用 parseFloat() 轉(zhuǎn)換數(shù)值的幾個典型示例:
var num1 = parseFloat ("1234blue") ; // 1234(整數(shù))
var num2 = parseFloat("0xA"); // 0
var num3 = parseFloat("22.5"); // 22.5
var num4 = parseFloat("22.34.5"); // 22.5
var num5 = parseFloat("0908.5"); // 908
var num6 = parseFloat("3.125e7"); // 31250000
==與===有什么區(qū)別?
x == y 在對比 x 和 y 的值之前,會嘗試對 x 和 y 做類型轉(zhuǎn)換,變成同一種類型后,再對比。
x===y會對比x和y是否同類型,不同類型會返回false,不會發(fā)生轉(zhuǎn)換。
== 會做類型轉(zhuǎn)換,=== 不做類型轉(zhuǎn)化
break與continue有什么區(qū)別
二者都是為了控制代碼循環(huán)執(zhí)行,執(zhí)行到之后都會立即跳出循環(huán)
break退出循環(huán)后,會繼續(xù)執(zhí)行后續(xù)的語句
for(var i=0;i<3;i++){
for(var j=0;j<3;j++){
console.log(j)
break
}
console.log('我')
}
//0
//'我'
//0
//'我'
//0
//'我'
continue退出循環(huán)后,會再從最外層循環(huán)開始執(zhí)行(注意外層循環(huán)次數(shù)沒有累加)
for(var i=0;i<2;i++){
for(var j=0;j<3;j++){
console.log(j)
continue
}
console.log('我')
}
//0
//1
//2
//"我"
//0
//1
//2
//"我"
void 0 和 undefined在使用場景上有什么區(qū)別
undefined 全局作用域下不能被重寫,但是在局部作用域中,可以被重寫的。所以undefined現(xiàn)常用于全局環(huán)境。
void 運算符通常只用于獲取 undefined 的原始值,一般使用 void(0)(等同于 void 0)。在上述情況中,也可以使用全局變量undefined 來代替(假定其仍是默認值)。
而 void 可以給任何給定的表達式求值,并返回 undefined,并且 void 不可被重寫,因此void 0是在局部作用域中替代undefined的最佳選擇 。
以下代碼的輸出結(jié)果及原因
console.log(1+1);
console.log(1+1); // 2
"+" 兩邊都是數(shù)值類型,做數(shù)值運算。
console.log("2"+"4");
console.log("2"+"4"); //24
"+" 兩邊都是字符串類型,直接拼接。
console.log(2+"4");
console.log(2+"4"); //24
"+" 一邊是數(shù)值類型,另一邊是字符串類型,數(shù)值類型轉(zhuǎn)為字符串類型后拼接。
console.log(+"4");
console.log(+"4"); //4
"+" 只有右側(cè)一個操作數(shù),轉(zhuǎn)換我數(shù)值類型。
以下代碼的輸出結(jié)果及原因
var a = 1;
a+++a;
typeof a+2;
var a = 1;
console.log(a+++a); //3
console.log(typeof a+2); //number2
因為"…++"優(yōu)先級高于"+"優(yōu)先級高于"++…","a+++a" 相當于"(a++)+a",即"1+2"返回 3 ;
"typeof a+2"相當于"(typeof a)+2",即"number+2",做字符串拼接返回number2。
以下代碼的輸出結(jié)果及原因
var a = 1;
var b = 3;
console.log( a+++b ); //4
因為"…++"優(yōu)先級高于"+"優(yōu)先級高于"++…","a+++b" 相當于"(a++)+b",即"1+3"返回 4;
遍歷數(shù)組,把數(shù)組里的打印數(shù)組每一項的平方
var arr=[3,4,5]
for(var i in arr){
console.log(arr[i]*arr[i])
}
//9
//16
//25
遍歷 JSON, 打印里面的值
var obj = {
name: 'hunger',
sex: 'male',
age: 28
}
for(var key in obj){
console.log(key+':'+obj[key])
}
//"name:hunger"
//"sex:male"
//"age:28"
以下代碼輸出結(jié)果及原因
var a = 1, b = 2, c = 3;
var val = typeof a + b || c >0
console.log(val)
//"number2"
優(yōu)先級:typeof>"+">"||",所以相當于"number2" || c>0,返回"number2"。
var d = 5;
var data = d ==5 && console.log('bb')
console.log(data)
//"bb"
//undefined
優(yōu)先級:"==">"+"&&",所以相當于true && undefined,返回undefined。
var data2 = d = 0 || console.log('haha')
console.log(data2)
//"haha"
//undefined
相當于data2=d=0|| undefined,0布爾值為false,所以返回undefined。
var x = !!"Hello" + (!"world", !!"from here!!");
console.log(x)
//2
優(yōu)先級:"=">"!">"+",相當于var x=true + (false,true),加號優(yōu)先將操作數(shù)轉(zhuǎn)為數(shù)字,所以得到2。