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运算符判断是存在类型转换