excel判断字符串包含另一个字符串_【前端冷知识】如何正确判断一个字符串是数值?...
在網(wǎng)頁中,我們從用戶輸入的內(nèi)容中獲取的值通常是字符串,但是有時(shí)候我們希望用戶輸入的內(nèi)容一定要能轉(zhuǎn)成數(shù)值:
<input?id="userInput">
userInput.addEventListener('change',?(e)?=>?{
??const?value?=?e.target.value;
??console.log(typeof?value);?// string
??console.assert(isNumeric(value),?`Not a numeric value:?${value}`);
});
即我們要實(shí)現(xiàn)一個(gè)isNumeric方法,判斷用戶輸入的值是能轉(zhuǎn)為數(shù)值的字符串。
我們討論isNumeric實(shí)現(xiàn)前,先說一下限制用戶輸入的方式。
?? 如果我們?cè)O(shè)置input的type為number,并不能保證輸入的內(nèi)容一定是數(shù)值,因?yàn)槿绻鹖nput的type是number,它依然可以輸入多個(gè)“+“、”-”、“.”、“e”。
<input?type="number"?step="0.0000001"?id="userInput">
input[type=number]并不阻止輸入多個(gè)e
這是因?yàn)椤?#43;/-”(正負(fù)符號(hào)),“.”(小數(shù)點(diǎn))和“e”(科學(xué)記數(shù)法)都是Number允許輸入的字符。
不過如果在form提交的時(shí)候,瀏覽器會(huì)對(duì)input[type=number]內(nèi)容再做一次檢查:
<form?id="myForm">
??<input?type="number">
??<input?type="submit">
form>
但是,不管怎樣,用戶還是可以通過修改頁面上的元素,繞過這些檢查,所以我們還是要用到isNumeric來判斷用戶輸入的合法性。
我們先看一下isNumeric應(yīng)該返回什么。
如果參考input[type=number]的規(guī)則,那么它應(yīng)該支持所有合法的有窮數(shù)值寫法:
function?isNumeric(str)?{
??...
}
console.assert(isNumeric('1000'));
console.assert(isNumeric('-100.'));
console.assert(isNumeric('.1'));
console.assert(isNumeric('-3.2'));
console.assert(isNumeric('001'));
console.assert(isNumeric('+4.5'));
console.assert(isNumeric('1e3'));
console.assert(isNumeric('1e-3'));
console.assert(isNumeric('-100e-3'));
console.assert(!isNumeric('++3'));
console.assert(!isNumeric('-100..'));
console.assert(!isNumeric('3abc'));
console.assert(!isNumeric('abc'));
console.assert(!isNumeric('-3e3.2'));
console.assert(!isNumeric('Infinity'));
console.assert(!isNumeric('-Infinity'));
console.assert(!isNumeric(''));
那么具體要怎么實(shí)現(xiàn)呢?
parseFloat?
有同學(xué)想到用parseFloat,這個(gè)行不行呢?
function?isNumeric(str)?{
??return?!Number.isNaN(parseFloat(str));
}
這個(gè)顯然是不行的,因?yàn)閜arseFloat('123abc')結(jié)果是123,因?yàn)閜arseFloat會(huì)嘗試轉(zhuǎn)部分?jǐn)?shù)值,而忽略掉不能轉(zhuǎn)數(shù)值的部分。
所以:
console.assert(!isNumeric('-100..'));
console.assert(!isNumeric('3abc'));
console.assert(!isNumeric('-3e3.2'));
這三個(gè)case是過不去的,另外這里用了Number.isNaN處理parseFloat之后的結(jié)果,由于±Infinity是數(shù)值,Number.isNaN會(huì)返回false,所以:
console.assert(!isNumeric('Infinity'));
console.assert(!isNumeric('-Infinity'));
也pass不了。
isNaN
有同學(xué)說,那我們直接使用isNaN如何?
function?isNumeric(str)?{
??return?!isNaN(str);
}
這次結(jié)果好得多,但是最后三條規(guī)則過不了:
console.assert(!isNumeric('Infinity'));
console.assert(!isNumeric('-Infinity'));
console.assert(!isNumeric(''));
±Infinity和上面的原因一樣,但是為什么''也pass不了呢?這是因?yàn)閕sNaN會(huì)先嘗試將參數(shù)轉(zhuǎn)為Number,而空字符串被轉(zhuǎn)為了數(shù)值0。
console.log(Number(''));?// 0
這里面就不得不提一下ECMA-262規(guī)范里面[[ToNumber]]的轉(zhuǎn)換規(guī)則了:
根據(jù)規(guī)則,Null、Boolean都會(huì)轉(zhuǎn)成Number,Undefined被轉(zhuǎn)成NaN,Undefined會(huì)被轉(zhuǎn)成NaN,而Symbol直接拋TypeError...
加上空字符串''被轉(zhuǎn)成0,isNaN就會(huì)有些怪異的行為了:
console.log(isNaN(undefined));?// true
console.log(isNaN(null));?// false
console.log(isNaN(true));?// false
console.log(isNaN(false));?// false
console.log(isNaN(''));?// false
其實(shí)字符串除了''還有一些:
console.log(isNaN(' '));?// false
console.log(isNaN(' '));?// false
console.log(isNaN('\t'));?// false
console.log(isNaN('\r'));?// false
console.log(isNaN('\n'));?// false
這就是為什么ES2015之后,又增加了Number.isNaN方法。
?? 冷知識(shí):isNaN方法對(duì)參數(shù)做[[ToNumber]]轉(zhuǎn)換,會(huì)導(dǎo)致一些比較怪異的結(jié)果,所以ES2015增加了Number.isNaN,該方法不會(huì)對(duì)參數(shù)做類型轉(zhuǎn)換,只要參數(shù)不是NaN,不管是什么類型,Number.isNaN一律返回false。
console.log(isNaN('abc'));?// true
console.log(Number.isNaN('abc'));?// false
console.log(isNaN(''));?// false
console.log(Number.isNaN(''));?// false
isFinite
我們把isNaN換成isFinite看看:
function?isNumeric(str)?{
??return?isFinite(str);
}
這下'±Infinity'的問題解決了,因?yàn)镹umber中的±Infinite和NaN的isFinite結(jié)果都返回false。
不過與isNaN一樣,isFinite也一樣會(huì)對(duì)參數(shù)進(jìn)行類型轉(zhuǎn)換,所以,這幾個(gè)case問題還是存在:
console.assert(!isNumeric(''));
console.assert(!isNumeric(' '));
console.assert(!isNumeric(' '));
console.assert(!isNumeric('\t'));
console.assert(!isNumeric('\r'));
console.assert(!isNumeric('\n'));
?? 冷知識(shí):isFinite與isNaN一樣,會(huì)對(duì)參數(shù)做[[ToNumber]]轉(zhuǎn)換,因此對(duì)應(yīng)的,ES2015也提供了一個(gè)Number.isFinite,這是不轉(zhuǎn)換參數(shù)類型的版本。如果參數(shù)不是Number類型,Number.isFinite一律返回false。
console.log(isFinite('123'));?// true
console.log(Number.isFinite('123'));?// false
console.log(isFinite(''));?// true
console.log(Number.isFinite(''));?// false
好了,那么討論到這里,最后的解決方法已經(jīng)呼之欲出了。
因?yàn)閷?duì)于isNumeric用法,我們只需要處理字符串,非字符串的case我們可以不管;那么我們剩下的就是處理這一堆字符串case:
console.assert(!isNumeric(''));
console.assert(!isNumeric(' '));
console.assert(!isNumeric(' '));
console.assert(!isNumeric('\t'));
console.assert(!isNumeric('\r'));
console.assert(!isNumeric('\n'));
這個(gè)有很多方式可以處理了,比如它們都匹配正則/^\s*$/,所以:
function?isNumeric(str)?{
??return?!/^\s*$/.test(str)?&&?isFinite(str);
}
這個(gè)版本就可以通過所有的case了。
另外,這些字符串的parseFloat都是NaN,所以,也可以這樣:
function?isNumeric(obj)?{
??return?!isNaN(parseFloat(obj))?&&?isFinite(obj);
}
實(shí)際上這個(gè)比上面那個(gè)正則的版本更好,因?yàn)檫@個(gè)還同時(shí)處理了非字符串的case,因?yàn)?#xff1a;
parseFloat(null);
parseFloat(true);
parseFloat(false);
上面這些的結(jié)果都是NaN。
實(shí)際上,上面這個(gè)版本就是著名的jQuery框架中的jQuery.isNumeric的實(shí)現(xiàn)方式。
因?yàn)楝F(xiàn)在不建議用isNaN和isFinite,而推薦使用Number.isNaN和Number.isFinite替代,所以一些linter的規(guī)則可能會(huì)禁止使用這兩個(gè)函數(shù),但是沒有關(guān)系,因?yàn)槲覀兛梢赃@么寫:
function?isNumeric(obj)?{
??return?!Number.isNaN(parseFloat(obj))
????&&?Number.isFinite(Number(obj));
}
所以,這個(gè)就是最終的版本。
原來,實(shí)現(xiàn)一個(gè)小小的函數(shù)isNumeric,有那么多需要注意的地方。
關(guān)于判斷字符串是數(shù)值,你還有什么想法,歡迎在issue中討論。
總結(jié)
以上是生活随笔為你收集整理的excel判断字符串包含另一个字符串_【前端冷知识】如何正确判断一个字符串是数值?...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 股票商誉规模是什么意思
- 下一篇: 开卡工本费要扣几次