上篇說了一些 JS 中數組操做的常見誤區,此次來總結一下初學者常見的其餘易錯點。html
當即執行函數(IIFE)在 JS 很是經常使用,做用就是構造一個函數級的變量做用域。常見的寫法以下:數據庫
(function () { // code })();
這樣寫可能會被 JS 理解成爲一個函數調用segmentfault
var a = 1 (function () { // Uncaught TypeError: 1 is not a function })()
從今天改變習慣,這樣寫:後端
void function () { // code }();
有些人喜歡以 !
打頭,我的習慣問題。數組
在 standardjs 規範日益流行的今天,忽略行尾分號成爲了主流(可是筆者不喜歡),更要改變這個習慣瀏覽器
注:standardjs 自己禁止行首括號(https://standardjs.com/readme...)安全
雖然不肯認可,JS 標準說:函數
typeof null === 'object' // true
毋庸置疑的,null
不具有做爲對象類型的基本特徵,是原始類型。這是一個廣爲人知的 JS 的 bug,,它從 JS 誕生開始就存在,從未、並且永遠不會被修復spa
咱們沒必要去探究它的黑歷史,可是咱們寫代碼時判斷一個變量的類型時,首先須要判斷它是否爲 null
調試
if (someVal !== null && typeof someVal === 'object') { // someVal 是一個對象 }
在 JS 裏,全部的 number 原始值都是一個雙精度浮點數,對應 Java 的 double 類型,對應標準 IEEE754。當心它的精度問題。
JS 最大可存儲的安全整數(不存在精度問題)爲 9007199254740991 (16位,Number.MAX_SAFE_INTEGER ),注意比 Java 的 long 類型最大整數 9223372036854775807 (19位) 小几個數量級,因此有時 JS 的 number 類型是不能精確存儲 Java 的整數的(固然一般狀況下不是問題)。
問題一般出在先後端數據傳輸上。數據庫中的主鍵一般是一個自增加的長整型數,有可能會超出 JS 的安全整數範圍,這時請考慮使用字符串傳輸。
例如:0.1+0.2 => 0.30000000000000004,0.4-0.3 => 0.10000000000000003
將小數轉化爲字符串時,永遠記得使用 toFixed 取小數點後若干位數字:
(0.1 + 0.2).toFixed(2) === '0.30'
比較小數相等時,切記不要直接使用 ===
,而要使用相減取絕對值的方式(表示兩數相差在必定範圍內即認爲他們相等)。
0.1+0.2 === 0.3 // false Math.abs(0.1+0.2 - 0.3) <= 1e-10 // true
NaN 之因此 NB,由於它有一個獨一無二的特性。對!獨一無二!那就是:
NaN === NaN // false var a = NaN; a === a // false
NaN
不等於它本身。你可使用這個特性判斷一個變量是否爲 NaN
,一個變量若是不等於它本身,這個變量必定是 NaN
。
還有一個方式是使用 Number.isNaN
。注意若是不已知這個變量的類型是數字時,不要使用 isNaN
作判斷,由於 isNaN 有個很詭異的特性:它會先將待判斷的變量轉換爲數值類型。
isNaN('abc') // true isNaN('123') // false isNaN('') // false isNaN([]) // false isNaN({}) // true
永遠不要寫 someVal === NaN
首先parseInt接受兩個參數,第一個參數爲待parse的字符串(若是不是字符串則會首先轉換爲字符串);第二個參數爲使用的進制數。
若是不傳第二個參數,則進制由第一個參數決定。什麼意思呢?好比以 0x 開頭的字符串,會被解析爲16進制數。
咱們知道以數字 0
開頭的數字爲8進制數(非嚴格模式),好比 011 === 9,0 自己也是8進制數。那麼問題來了, parseInt('011') = ?
答案是看瀏覽器。目前絕大多數瀏覽器都會做爲10進制數解析,結果爲11。可是還有一些老舊的瀏覽器以8進制數解析(例如IE8和一批老Android瀏覽器)
因此若是你非要用 parseInt:
parseInt
使用規則一:請傳入第二個參數回到 parseInt 自己的含義。顧名思義這個函數是在parse,被parse的必定是個字符串。若是第一個參數不是字符串,那麼會首先被轉換爲字符串。
問:parseInt(0.0000000008)
=?
答:
本身打開調試器去試
建議對於數值轉換一律使用強制轉換函數 Number,若是你JS用6了可使用 +
(正號)。
若是須要對某個數字取整,建議使用 Math.trunc。若是你能肯定數值在 32 位之內,可使用 x | 0
或 ~~x
等方式
parseInt的用處在於轉換一些CSS裏帶單位的值:parseInt('10px', 10)
=> 10。但這裏建議使用parseFloat,能夠解析小數又沒有進制問題。
==
毫不要簡單的把非嚴格相等 ==
理解爲二者表示的數字同樣,它有一套很是複雜的轉換規則:它會先將 %%
轉換爲 @@
,而後把 !!
轉換爲 **
,若是 %%
是 ??
類型,還會 xx
一把……
看不懂對吧,我相信你就算看懂了也記不住的。否則請問:
'true' == true // => false 'true' == false // => false [] == {} // => false [] == [] // => false
關於非嚴格相等,你只須要記住這個規則:
null == null // => true undefined == undefined // => true null == undefined // => true undefined == null // => true x == null // => false (x 非 null 或 undefined) x == undefined // => false (x 非 null 或 undefined)
簡言之:
x == null // 或 x == undefined
是最簡單的判斷 x 爲 null 或 undefined 的方式,相對應的
x != null // 或 x != undefined
是最簡單的判斷 x 非 null 和 undefined 的方式。這就是 ==
存在的惟一意義。
因爲可能的歷史傳承緣由,JS 內置對象 Date 的構造函數比較特殊。
year
是 0 ~ 99 之間,year 默認加 1900。好比 1 表明公元 1901 年,99 表明公元 1999 年,100 表明公元 100 年。(你問 -1 是幾?公元前 1 年。。。)month
從 0 開始算。0 表明一月,1 表明二月,以此類推。12 表明下一年的一月(自動進位)第一點不知道也沒什麼,畢竟通常不會操做公元 99 年以前的時間。但第二點就很容易出錯,切記它是以 0 開始的數字。
這樣獲得的日期對象是本地時間(採用客戶端時區)
時常有後端接口返回一個日期字符串的狀況:
new Date('2018-01-01') // => "2018/1/1 08:00:00" 新版瀏覽器,IE 11 new Date('2018-01-01') // => "2018/1/1 00:00:00" 某些舊版安卓 new Date('2018-01-01') // => "Invalid Date" IE 8(這個忽略。。。)
能夠看到,瀏覽器基本都是把日期字符串當作 UTC 時間處理的。而
new Date('2018/01/01') // => "2018/1/1 00:00:00" 包括 IE 8 在內全部瀏覽器
因此對於日期字符串,請注意字符串中是使用橫槓仍是斜槓。對於橫槓能夠考慮將 -
替換成 /
,或者補全完整的帶時區的 ISO8601 字符串。考慮到負數時區的問題,不推薦將小時數清零的作法。
PS:將日期對象取當天 0 點爲 date.setHours(0, 0, 0, 0)
PS2:取當前時間的 Unix 時間戳能夠 Date.now()
||
填充默認值這反而是 JS 老鳥更容易犯的錯誤。給用戶傳入的對象填充默認值是很常見的行爲,他們老是隨手就寫:
config.prop1 = config.prop1 || 233; config.prop2 = config.prop2 || 'balabala';
expr1 || expr2
的意思是:若是expr1能轉換成true則返回expr1,不然返回expr2
expr1 || expr2 <=> Boolean(expr1) ? expr1 : expr2
哪些值不能轉換爲 true 呢?
若是用戶指定了傳入參數的值爲 0 或者是空字符串的配置項,它的值就會被強制替換爲默認值,然而實際上只有 undefined
應該被認爲是用戶沒有指定其值(語義上能夠這樣理解:null
表示 用戶讓你給他把這個位置空着
;而 undefined
表示 用戶沒發表意見
)
因此就應該是這樣:
config.prop1 = config.prop1 !== undefined ? config.prop1 : 233; config.prop2 = config.prop2 !== undefined ? config.prop2 : 'balabala';
很長。。。你能夠搞個全局的函數簡化這一操做,或者考慮使用 lodash 的 defaults 方法
歡迎補充