前端技術的發展速度你們有目共睹,js的ECMA標準也再也不是3的天下,但無論再怎麼山雨欲來風滿樓,基礎語法仍是得溫故而知新。不管你是初學則仍是多年js的編程者,均可以試着作作下面的測試題,我相信總仍是會有些收穫的。由於所有是本身總結和手打的,有紕漏錯誤之處請留言,謝謝。javascript
一:考察基本數據類型與運算符前端
(1)未定義變量問題java
var a; console.log(typeof a); ==>undefined
先以一個最多見也是最簡單的測試案例開始,未定義的變量或者未賦值則爲undefined編程
(2)++/--運算符問題數組
var a = '1a'; console.log(a++); ==>NaN
++操做符將對a變量隱式轉換爲number類型,字符串'1a'沒法正常轉換爲數字,因此返回NaN。函數
這裏能夠總結出如下幾點:測試
1. 除了+操做符之外,-、*、/、%、++、--都將隱式轉換參與運算的變量爲number類型,若是能正常轉換爲數字則返回該數字,不然返回NaN;spa
2. 能正常轉換爲數字的有以下幾種狀況:prototype
純數字類字符串如'123'、'1e2'(轉換爲1*10的2次方等於100);對象
null參與運算轉換爲0(null-4等於-4,null+null等於0);
boolean類型的true和false分別可轉換爲1和0;
3. 只有可以轉換爲數字的變量才能參與++或--運算,不然將報錯,好比:
console.log(3++); ==>報錯,常量不能直接運算++ var a = 3; console.log(a++); ==>3
其中有個特例:NaN++能夠正常返回結果,仍然是NaN
(3)+運算符之四則運算與字符合並
console.log(2+'1'); ==>'21' console.log(2-'1'); ==>1 console.log(1+NaN); ==>NaN console.log('1'+NaN); ==>'1NaN'
1. +運算符有必要單獨一提,由於除了+之外的其它算術運算符,都會對參與運算的變量或值默認隱式轉換爲number,但+由於在js中還肩負着字符串合併的重大任務,因此它有特殊'國情':
1.1 當+的左右兩邊均是數字類型時,則執行算術運算,好比1+2返回三、NaN+1返回NaN;
1.2 當+的左右兩邊均是字符串類型時,則執行字符串合併,好比'1'+'2'返回'12';
1.3 當+的左右兩邊一個是數字、一個是字符串類型時候,則先將數字轉換爲字符串再合併,好比1+'1'返回'11';
2. 在實際開發過程當中,咱們使用+運算符基本上都是處理字符串類型或者數字類型的,因此上面的三種狀況可以應對大部分開發場景。可是當+運算符的左右兩邊出現了第三種數據類型時,狀況就會顯得複雜了(如下其它數據類型是指除了string和number的之外類型):
2.1 其它數據類型+字符串類型
console.log(null+'1'); ==>'null1' console.log(undefined+'1'); ==>'undefined1' console.log([1,2]+'1'); ==>'121' console.log((function(){})+'1'); ==>'function (){}1' console.log(({})+'1'); ==>'[object Object]1'
執行辦法:其它數據類型將被轉換爲字符串再合併,且對象類型將調用自身toString()方法轉換結果。另外,其實對象類型+運算不管另一個參與運算的值是否是字符串類型,都只能與它進行字符串合併操做,而不能是四則運算,下面會具體講到。
2.3 其它數據類型+數字類型
console.log(null+1); ==>1 console.log(undefined+1); ==>NaN console.log(true+1); ==>2 console.log([1]+1); ==>'11' console.log((function(){})+1); ==>'function (){}1' console.log(({})+1); ==>'[object Object]1'
執行辦法:非對象類型將進行四則運算,而對象類型場景則仍然是字符串合併的操做。
2.2 其它數據類型+其它數據類型
console.log(null+null); ==>0 console.log(undefined+undefined); ==>0 console.log(true+true); ==>2 console.log([1]+[2]); ==>'12' console.log((function(){})+(function(){})); ==>'function (){}function (){}' console.log(({})+({})); ==>'[object Object][object Object]'
執行辦法:非對象類型將進行四則運算,而對象類型場景則仍然是字符串合併的操做。
因此,關於有其它類型參與+運算的場景,咱們能夠再稍總結下最終的結果:只要有對象類型參與+運算,則永遠是作字符串合併;若是是null/undefined/boolean類型參與+運算,當另外一個參與運算的值爲字符串,則進行字符串合併,不然進行四則運算。
思考題:alert({name:'mofei'})
(4)+運算符之轉換數字問題
console.log(1+ +1); ==>2 console.log(1e+1+1); ==>11
這個測試仍然是+運算,可是並無和上一個測試案例合併在一塊兒而是單獨出來,緣由很簡單:此+非彼+。
+運算符實際上在js中有三種應用場景:轉換爲數字、四則運算加、字符串鏈接。在上一個測試案例中咱們講了後兩種應用場景,而這裏是則是對第一個應用場景的補充。關於轉換爲數字的理解也不難,咱們常常用a+''的寫法將一個變量轉換爲字符串類型,因此咱們也能夠利用+運算符將其它類型轉換爲數值類型,好比+null返回結果爲0。因此在這個案例中,1+ +1等同與1+1,由於後面那個+1其實就是將1轉換爲number類型,仍然是1,而1e+1+1等效於1e1+1,也就是11。
(5)除/取模運算符的極端場景問題
console.log(10/0); ==>Infinity console.log(10%0); ==>NaN
除0返回Infinity,對0取模(求除法運算的餘數,對2取模經常使用在判斷奇偶)返回NaN。
(6)!運算符問題
console.log(!!false); ==>false console.log(!!4); ==>true console.log(!!'false'); ==>true
這裏考察了取反運算符。雙取反實際上就是將運算對象強制轉換爲boolean型,其中最後一個要注意'false'自己是個非空字符串,轉換爲布爾值爲true。
大部分狀況下轉布爾值都是返回true,除了如下幾種狀況:false自己、null、nudefined、空字符串''、數字0、數字NaN
思考題:!!undefined
(7)typeof運算符問題
console.log(typeof(0)); ==>number
console.log(typeof(NaN)); ==>number console.log(typeof('0')); ==>string console.log(typeof('false')); ==>string console.log(typeof(false)); ==>boolean console.log(typeof(undefined)); ==>undefined console.log(typeof(null)); ==>object console.log(typeof([1,2])); ==>object console.log(typeof(function(){})); ==>function
這裏羅列了typeof能夠返回的全部可能值:number、string、boolean、undefined、object、function
能夠總結的知識點是:
1. 凡是帶上引號的typeof就是string,而不須要管裏面內容是什麼,好比不要誤覺得typeof('undefined')結果就是undefined
2. null、數組array、普通對象的typeof返回爲object
3. 函數自己也是對象,可是它的typeof返回爲特殊的function
4. 並不能依靠typeof所有分別出變量到底屬於8種數據類型中的哪種(好比數組和普通對象),可是能夠直接區分基本數據類型中的四種類型:number、string、boolean、undefined,若是要所有區分類型能夠結合其它方法共同判斷(如instanceof、constructor),或者使用Object.prototype.toString.call(...)
(8)寬鬆等於嚴格等問題
console.log(null == undefined); ==>true console.log(false == ''); ==>true console.log(false === !true); ==>true console.log([] === []); ==>false
關於等於運算符==:比較雙方是否相等,這種比較是容許進行類型轉換的,好比1 == '1'將返回true,至於它們是怎樣進行類型轉換能夠參照《javascript權威指南》75頁有很是詳細的描述,這裏再也不闡述了。嚴格等運算符常常在對象的比較中被考察,咱們要知道對象的比較是經過引用比較的,因此在這個測試案例中,它們雖然看上去很像,實際上是兩個不一樣的對象(這裏也是數組),它們並無引用同一個地址,因此並不嚴格等,對象嚴格等的狀況以下:
var a = []; var b = a; console.log(a === b); ==>true
b變量被賦值爲a,a本質是對象,對象賦值爲引用賦值,此時a和b公用一個地址,因此嚴格等成立。
此外,關於==還有個比較經典的問題:
console.log([] == ![]); ==>true
由於!運算符優先級緣由,將先執行![],因此這裏等效於 [] == false,按照常識在boolean環境下空數組是轉換爲true的,可是實際上在==環境中,是經過轉換爲數字或字符串來比較的,當操做值有boolean類型時轉換爲數值比較,也就是[]轉換爲number類型爲0,false轉換爲number類型爲0,因此結果返回true。看上去這些繁瑣的轉換實在使人擔心,但實際也沒有這麼糟糕,畢竟這種看上去「非人性」的結果在實際開發場景中極少遇到,當你有必定的經驗的時候,絕大部分寬鬆相等的結果你仍是可以一眼識破的。
(9)或與問題
console.log(1&&2); ==>2 console.log(1||2); ==>1 console.log(1&&a=2); ==>error console.log(1&&(a=2)); ==>2
關於&&和||兩個運算符,也是筆試中的常客。這裏有幾點須要注意:
1. &&和||返回的是表達式的值,而並非true或者false
2. 從左到右執行,&&左側的表達式返回值若是轉換布爾型爲true時,則將執行右側的表達式;||左側的表達式返回值若是轉換布爾型爲true時,則直接返回該表達式返回值且再也不執行右側表達式
有了以上兩點,前兩個測試則比較容易理解了,而對於1&&a=2,實際等同於——(1&&a)=2——undefined=2,執行將報錯;只要給a=2加上小括號優先執行則能夠正常運行,其中a=2的返回值爲2,因此最終表達式的值爲2。
(10)浮點數字不精確問題
console.log(0.1*0.1); ==>0.010000000000000002
在js中採用的是一種二進制表示法,能夠精確的表示分數,好比1/2、1/8、1/1024。可是其它浮點值實際上只是真實值的一個近視表示,好比0.1,二進制浮點數表示法並不能精確的表示0.1這樣簡單的數字。因此,當遇到小數點的四則運算的時候須要特殊處理,最典型的場景就是支付了,好比1.1元每一個,用戶購買3個,則不能直接使用相乘結果,可使用toFixed控制結果,或者以乘法爲例可以使用如下方法保證精確性:
//乘法處理 function FloatMul(arg1,arg2) { var m=0,s1=arg1.toString(),s2=arg2.toString(); try{m+=s1.split(".")[1].length}catch(e){} try{m+=s2.split(".")[1].length}catch(e){} return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m); }