JavaScriptのArray.includes()遅すぎぃぃ！【Array.includes() vs key in Object vs Set.has() vs Map.has()】

100万件の文字に任意の文字が含まれるか選手権を開催いたします。

# TL;DR

![ops_s と 方法 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/315f556b-1010-47ba-1ca1-8038831ada07.png)

V8に最適化なんて入ってなかった

https://jsbench.me/rzleftsjtj/1

# セットアップ
```javascript
const array = Array(1000000).fill().map(()=>Math.random().toString().slice(-8))
const object = Object.fromEntries(array.map(a => [a]))
const map = new Map(array.map(a => [a]))
const set = new Set(array)
```

# Array.includes() 251 ops/s
```javascript
array.includes(Math.random().toString().slice(-8))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/1a82a85d-ed13-2825-5860-11a8e06d9583.png)


# Array.indexOf() 229 ops/s
```javascript
array.indexOf(Math.random().toString().slice(-8))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/2db59969-8e28-af5b-1dca-42d695a53861.png)


# Object[key] 1,957,463 ops/s
```javascript
object[Math.random().toString().slice(-8)]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/20381f57-097a-69f9-aa56-49a374b65980.png)

# Object.hasOwnProperty() 2,217,807 ops/s
```javascript
object.hasOwnProperty(Math.random().toString().slice(-8))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/9dca8d7f-12b3-f054-cfd0-a5998ad5ff99.png)


# key in Object 2,193,181 ops/s
```javascript
Math.random().toString().slice(-8) in object
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/1492aa08-a1b6-67dc-e95b-b6536e5ef0d8.png)


# Map.has() 1,430,881 ops/s
```javascript
map.has(Math.random().toString().slice(-8))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/7ba1b7f4-d841-4652-4a0c-d40d7ef8e5b4.png)


# Set.has() 1,783,334 ops/s
```javascript
set.has(Math.random().toString().slice(-8))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/6fd20f88-8a73-18ac-fe76-9a71ea6cca75.png)


# for 205 ops/s
```javascript
const target = Math.random().toString().slice(-8)
let exists = false
const length = array.length
for(var i = 0; i < length; i++) {
    if (array[i] === target) {
        exists = true
        break
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/7c1914f0-0bde-a7c8-2622-14d9abe4ba4b.png)


# Node.js

`key in Object`が最速っぽい？

```bash
array.includes(Math.random().toString().slice(-8)) 255.31212026521055
array.indexOf(Math.random().toString().slice(-8)) 273.96164583508994
object[Math.random().toString().slice(-8)] 1377596.804375387
object.hasOwnProperty(Math.random().toString().slice(-8)) 1686838.1590012764
Math.random().toString().slice(-8) in object 1750538.4657379298
map.has(Math.random().toString().slice(-8)) 1347472.81481226
set.has(Math.random().toString().slice(-8)) 1391667.3915078628
```

```javascript
const array = Array(1000000).fill().map(() => Math.random().toString().slice(-8))
const object = Object.fromEntries(array.map(a => [a]))
const map = new Map(array.map(a => [a]))
const set = new Set(array)

const functions = [
    () => array.includes(Math.random().toString().slice(-8)),
    () => array.indexOf(Math.random().toString().slice(-8)),
    () => object[Math.random().toString().slice(-8)],
    () => object.hasOwnProperty(Math.random().toString().slice(-8)),
    () => Math.random().toString().slice(-8) in object,
    () => map.has(Math.random().toString().slice(-8)),
    () => set.has(Math.random().toString().slice(-8)),
]

for (const func of functions) {
    const iters = 10000
    const now = performance.now()
    Array(iters).fill().forEach(func)
    console.log(func.toString().slice(6), iters / (performance.now() - now) * 1000)
}
```

Google Cloud Shell
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/f8fd6dd5-ab81-3a7b-9934-807108424a8b.png)

AWS Lambda

```bash
START RequestId: 27e4dd98-6b69-471f-93c6-18b8e7c60a9b Version: $LATEST
2023-02-24T00:19:42.323Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	array.includes(Math.random().toString().slice(-8)) 100.11041055746443
2023-02-24T00:21:09.727Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	array.indexOf(Math.random().toString().slice(-8)) 114.41227075738253
2023-02-24T00:21:09.738Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	object[Math.random().toString().slice(-8)] 956500.0058246729
2023-02-24T00:21:09.748Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	object.hasOwnProperty(Math.random().toString().slice(-8)) 1057379.8824432148
2023-02-24T00:21:09.757Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	Math.random().toString().slice(-8) in object 1051999.1613521294
2023-02-24T00:21:09.770Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	map.has(Math.random().toString().slice(-8)) 840604.0681615262
2023-02-24T00:21:09.781Z	27e4dd98-6b69-471f-93c6-18b8e7c60a9b	INFO	set.has(Math.random().toString().slice(-8)) 885716.8416465283
END RequestId: 27e4dd98-6b69-471f-93c6-18b8e7c60a9b
REPORT RequestId: 27e4dd98-6b69-471f-93c6-18b8e7c60a9b	Duration: 189717.39 ms	Billed Duration: 189718 ms	Memory Size: 10240 MB	Max Memory Used: 517 MB	Init Duration: 212.71 ms	
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127414/c0a17794-1c37-ba6a-ab42-e8081e8317d2.png)


# まとめ
- 要素数が少ないなら、`Array.includes(key)`
- 短く書きたいなら、`key in Object`
- notもつけたいなら `!object.hasOwnProperty(key)`