JavaScript中的in运算符与数组

前言

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 离谱
复制代码

image.png 发生甚么事啦。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运算符会返回数组的类型是objectprototype

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
复制代码

规定

  • 点式不能使用数字,不然识别为小数,报错。

  • 键名传入非字符串时,会被转为字符串

正所以,数组才能使用数字索引访问。而数组中的键都是字符串。

in 运算符 与包含

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.0.toString ()与(1).toString()

这个问题也是个笔试常考题目。首先是不能写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呢?

俺也不知道

3n是什么?

前文的内容彻底解释了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

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

相关文章
相关标签/搜索