JavaScript中有不少怪異點,這個in運算符後接數組就很奇特(雖然你們不多用到這個)。語義上講in是個介詞,詞性prep,表示在什麼什麼裏面。但在js中可能就不太同樣了。python
不慌,先來看看python中的效果。算法
>>> array = [1,2,3,4]
>>> 0 in array
False
>>> 4 in array
True
>>> 4.0 in array
True
>>> 4n in array
SyntaxError: invalid syntax
複製代碼
顯然,此處in就是表示判斷左邊的元素是否存在與數組中。數組
>>> 4==4.0
True
>>> array.append('5')
>>> 5 in array
False
複製代碼
挨個匹配的,若是相等則返回True,顯然字符串‘5’和數字5並不相等。很是合理是否是。瀏覽器
再來看看瀏覽器中的狀況。markdown
let a = [1,2,3,4];
1 in a;//true 合理
1.0 in a;//true
0 in a;//true 合理嗎?
'1' in a;//true
3n in a;//true 離譜
複製代碼
發生甚麼事啦。app
一塊兒來研究下。oop
數組Array 時按次序排列的一組值。每一個值的位置都有編號(從0開始),整個數組用方括號表示。ui
任何類型的數組均可以放入數組。spa
let array = [a,2,[3,4]];// a 是[1,2,3,4]
array
(3) [Array(4), 2, Array(2)]
複製代碼
數組實際上一種的對象。typeof
運算符會返回數組的類型是object
prototype
typeof a ;//"object"
Object.keys(a);//(4) ["0", "1", "2", "3"]
複製代碼
這裏能夠看出來,數組的鍵全是字符串數組,從0開始。
來看看對象的設定,js中的規定,對象的鍵都的是字符串。
當訪問對象的值是,有點式object.key和括號式object[key]。
let ob = {'0':0,'1':1,'k':'v'};
ob.k ;//"v"
ob["k"];
"v" // 兩種都能取值
ob.0 // 報錯啦!數字加點,還覺得是小數
Uncaught SyntaxError: Unexpected number
ob['0'] //數字字符串沒毛病
0
ob[0] //[]內爲數字時,也能訪問
0
複製代碼
規定:
點式不能使用數字,不然識別爲小數,報錯。
鍵名傳入非字符串時,會被轉爲字符串
正所以,數組才能使用數字索引訪問。而數組中的鍵都是字符串。
MDN上的解釋是這樣的:
若是指定的屬性在指定的對象或其原型鏈中,則**in
運算符**返回true
。
顯然這個in並非包含關係,而是包含該屬性。
"toString" in {}; //true
複製代碼
in
右操做數必須是一個對象值,不能是字符串。而左側須要一個字符串,
當左側傳入不是字符串時,則調用tostring(),轉爲字符串.
順帶一提,要表達包含關係,可使用Array.prototype.includes() ,例如:
[1, 2, NaN].includes('1');//false
[1, 2, NaN].includes(1.0);//true
[1, 2, NaN].includes(NaN);//true
複製代碼
這個問題也是個筆試常考題目。首先是不能寫1.toString(),由於有歧義,不知道這個.是小數點,仍是調用方法。只要能規避歧義的,都能獲得正確的結果。好比:
1 .toString;//'1'
(1).toString();//'1'
1.0.toString();//'1'
複製代碼
如今的問題是爲何1.0.toString()獲得的是字符串'1',而不是字符串’1.0‘呢?
1.0 === 1;//true
複製代碼
從存儲上來說,JavaScript數字所有是浮點數。 根據 IEEE 754標準中的64位二進制(binary64), 也稱做雙精度規範(double precision)來儲存。那麼1.0===1也合情合理。
在toString ()的實現算法中,是根據數字的大小來將數字解碼成字符串的。具體太複雜了,能夠看這個
所以1.0 或是1.00,乃至是1.0000000000000001.toString() 都是’1‘ (精度不夠了)。
那麼問題來了,有沒有數tostring()能夠獲得1.0呢?
俺也不知道
前文的內容徹底解釋了1.0 in a 和’1‘ in a獲得true的問題,可是最後一個3n 是什麼呢。
答案是ES2020新特性:一個用於處理任意精度整數的新數字基元--n
爲了更精確地表示沒有位數限制的整數,ES2020引入了不一樣於Number
數字類型的BigInt
數字類型, 只用來表示整數(大整數),沒有位數的限制
,任何位數的整數均可以精確表示。爲了與 Number 類型區別,BigInt 類型的數據必須添加後綴n
。
typeof 3n //"bigint"
3n ==3;//true
3n === 3;//false
3n+4n;//7n
3n.toString();//"3"
複製代碼
因此3n in [1,2,3,4] ===true很是合理。
那麼1.0n.tostring() 能獲得1.0嗎?固然,報錯了。bigInt只能用於整數。
坐等ES2035修復小數的精度問題。
for in 能夠用與遍歷,跟in差很少意思,用於遍歷獲得的是索引。
遍歷數組時,固然獲得的是字符串而不是數字。
for (let i in [1,2,3]){console.log(2+i)};
//20
//21
//22
複製代碼
也能遍歷到原型鏈上的屬性。
let a = [1,2,3,4];
a.k='v';
Array.prototype.key='val';
for (let i in a){console.log(i)};
0
1
2
3
k
key
複製代碼
ES6的for of,用於遍歷數組。
for (let i of a){console.log(i)}
1
2
3
4 //到4就結束了,拿不到屬性k
複製代碼
for of 遍歷對象或類數組會報錯。
綜上:for in 適合遍歷對象
for of 遍歷數組
js中的in不是表示包含關係,並且表示屬性存在與否
數組中的屬性均爲字符串,in運算符判斷是存在類型轉換