>웹 프론트엔드 >JS 튜토리얼 >JavaScript 배열 연산의 기본

JavaScript 배열 연산의 기본

小云云
小云云원래의
2017-12-18 16:10:001366검색

이 기사에서는 주로 JavaScript 배열 작업의 기본 사항을 공유합니다. for_in을 사용하여 배열을 탐색하지 마세요. 이는 JavaScript 초보자들이 흔히 저지르는 오해입니다. for_in은 프로토타입 체인을 포함하여 객체의 모든 열거 가능한(열거 가능한) 키를 탐색하는 데 사용됩니다. 원래는 배열 탐색을 위해 존재하지 않습니다.

for_in을 사용하여 배열을 순회하는 데에는 세 가지 문제가 있습니다.

  1. 순회 순서가 고정되어 있지 않습니다.

JavaScript 엔진은 객체의 순회 순서를 보장하지 않습니다. 배열을 일반 객체로 순회하는 경우 순회 인덱스 순서도 보장되지 않습니다.

  1. 은 객체 프로토타입 체인의 값을 순회합니다.

배열의 프로토타입 객체(예: 폴리필)를 <code><span style="font-size: 14px;">enumerable: false</span>,for_in 会把这些东西遍历出来。

  1. 运行效率低下。

尽管理论上 JavaScript 使用对象的形式储存数组,JavaScript 引擎还是会对数组这一非常常用的内置对象特别优化。  https://jsperf.com/for-in-vs-...  
可以看到使用 for_in 遍历数组要比使用下标遍历数组慢 50 倍以上

PS:你可能是想找 for_of

不要用 JSON.parse(JSON.stringify()) 深拷贝数组

有人使用 JSON 中深拷贝对象或数组。这虽然在多数情况是个简单方便的手段,但也可能引发未知 bug,因为:

  1. 会使某些特定值转换为 <span style="font-size: 14px;">null</span>

NaN, undefined, Infinity 对于 JSON 中不支持的这些值,会在序列化 JSON 时被转换为 null,反序列化回来后自然也就是 null

  1. 会丢失值为 undefined 的键值对

JSON 序列化时会忽略值为 undefined 的 key,反序列化回来后自然也就丢失了

  1. 会将 Date 对象转换为字符串

JSON 不支持对象类型,对于 JS 中 Date 对象的处理方式为转换为 ISO8601 格式的字符串。然而反序列化并不会把时间格式的字符串转化为 Date 对象

  1. 运行效率低下。

作为原生函数,<span style="font-size: 14px;">JSON.stringify</span><span style="font-size: 14px;">JSON.parse</span> 自身操作 JSON 字符串的速度是很快的。然而为了深拷贝数组把对象序列化成 JSON 再反序列化回来完全没有必要。

我花了一些时间写了一个简单的深拷贝数组或对象的函数,测试发现运行速度差不多是使用 JSON 中转的 6 倍左右,顺便还支持了 TypedArray、RegExp 的对象的复制

https://jsperf.com/deep-clone...

不要用 arr.find 代替 arr.some

<span style="font-size: 14px;">Array.prototype.find</span> 是 ES2015 中新增的数组查找函数,与 <span style="font-size: 14px;">Array.prototype.some</span> 有相似之处,但不能替代后者。

<span style="font-size: 14px;">Array.prototype.find</span> 返回第一个符合条件的值,直接拿这个值做 <span style="font-size: 14px;">if</span> 判断是否存在,如果这个符合条件的值恰好是 0 怎么办?

<span style="font-size: 14px;">arr.find</span> 是找到数组中的值后对其进一步处理,一般用于对象数组的情况;<span style="font-size: 14px;">arr.some</span>enumerable: false로 설정하지 않고 변경하면 for_in은 이러한 항목을 반복합니다.

🎜🎜🎜🎜🎜비효율적인 운영. 🎜🎜🎜🎜🎜🎜이론적으로 JavaScript는 객체 형식을 사용하여 배열을 저장하지만 JavaScript 엔진은 특히 매우 일반적으로 사용되는 내장 객체인 배열에 최적화되어 있습니다. https://jsperf.com/for-in-vs-...
for_in을 사용하여 배열을 순회하는 것이 첨자를 사용하여 배열을 순회하는 것보다 50배 이상 느리다는 것을 알 수 있습니다🎜🎜🎜🎜PS: for_of🎜🎜🎜🎜배열 딥 카피에 JSON.parse(JSON.stringify())를 사용하지 마세요🎜🎜🎜🎜어떤 사람들은 객체나 배열 딥 카피에 JSON을 사용합니다. 이는 대부분의 경우 간단하고 편리한 방법이지만 다음과 같은 이유로 알 수 없는 버그가 발생할 수도 있습니다. 🎜🎜🎜🎜🎜🎜은 일부 특정 값을 🎜🎜null🎜🎜🎜🎜🎜🎜으로 변환합니다. NaN, 정의되지 않음, Infinity. JSON에서 지원되지 않는 값의 경우 JSON을 직렬화할 때 null로 변환되며 역직렬화 후에는 자연스럽게 null🎜🎜🎜🎜🎜🎜이 됩니다. 정의되지 않은 값은 손실됩니다🎜🎜🎜🎜🎜JSON은 직렬화 중에 정의되지 않은 값이 있는 키를 무시하고 역직렬화 후에는 손실됩니다. 🎜🎜🎜🎜🎜🎜 날짜 개체를 문자열로 변환합니다🎜🎜🎜🎜🎜🎜 JSON은 Object 유형을 지원하지 않으므로 JS에서 Date 객체를 처리하는 방법은 ISO8601 형식의 문자열로 변환하는 것입니다. 그러나 역직렬화는 시간 형식 문자열을 Date 개체로 변환하지 않으므로 비효율적입니다. 🎜🎜🎜🎜🎜🎜기본 함수인 🎜🎜JSON.stringify🎜🎜 및 🎜🎜JSON.parse🎜🎜은 자체적으로 JSON 문자열을 매우 빠르게 작동합니다. 그러나 배열을 심층 복사하기 위해 개체를 JSON으로 직렬화하고 다시 역직렬화하는 것은 전혀 필요하지 않습니다. 🎜🎜🎜🎜배열이나 객체의 간단한 전체 복사 기능을 작성하는 데 시간을 투자했는데 테스트 결과 실행 속도가 JSON 전송을 사용할 때보다 거의 6배나 빠른 것으로 나타났습니다. 그런데 TypedArray 및 복사도 지원합니다. RegExp 개체🎜🎜🎜 🎜https://jsperf.com/deep-clone...🎜🎜🎜🎜arr.some🎜🎜🎜🎜Array.prototype.find🎜🎜는 ES2015의 새로운 기능입니다. 추가된 배열 검색 기능은 🎜<code>🎜Array.prototype.some🎜🎜과 유사하지만 후자를 대체할 수는 없습니다. 🎜🎜🎜🎜Array.prototype.find🎜🎜 첫 번째 정규화된 값을 반환합니다. 이 값을 직접 사용하여 🎜🎜if🎜🎜을 수행하여 해당 값이 존재하는지 확인합니다. 정규화된 값이 정확히 0인 경우 어떻게 해야 합니까? 🎜🎜🎜🎜arr.find🎜🎜는 배열의 값을 찾은 후 추가 처리하는 것입니다. 일반적으로 객체 배열의 경우에 사용됩니다. /code>🎜는 둘이 섞일 수 없는지 확인하는 것입니다. 🎜🎜

arr.forEach 대신 arr.map을 사용하지 마세요

JavaScript 초보자가 자주 범하는 실수는 <code><span style="font-size: 14px;">Array.prototype.map</span><span style="font-size: 14px;">Array.prototype.forEach</span> 的实际含义。

<span style="font-size: 14px;">map</span> 中文叫做 <span style="font-size: 14px;">映射</span>,它通过将某个序列依次执行某个函数导出另一个新的序列。这个函数通常是不含副作用的,更不会修改原始的数组(所谓纯函数)。

<span style="font-size: 14px;">forEach</span> 就没有那么多说法,它就是简单的把数组中所有项都用某个函数处理一遍。由于 <span style="font-size: 14px;">forEach</span> 没有返回值(返回 undefined),所以它的回调函数通常是包含副作用的,否则这个 <span style="font-size: 14px;">forEach</span> 写了毫无意义。

确实 <span style="font-size: 14px;">map</span><span style="font-size: 14px;">forEach</span> 更加强大,但是 <span style="font-size: 14px;">map</span> 会创建一个新的数组,占用内存。如果你不用 <span style="font-size: 14px;">map</span> 的返回值,那你就应当使用 <span style="font-size: 14px;">forEach</span>

补:forEach 与 break

ES6 以前,遍历数组主要就是两种方法:手写循环用下标迭代,使用 <span style="font-size: 14px;">Array.prototype.forEach</span>。前者万能,效率最高,可就是写起来比较繁琐——它不能直接获取到数组中的值。

笔者个人是喜欢后者的:可以直接获取到迭代的下标和值,而且函数式风格(注意 FP 注重的是不可变数据结构,forEach 天生为副作用存在,所以只有 FP 的形而没有神)写起来爽快无比。但是!不知各位同学注意过没有:forEach 一旦开始就停不下来了。。。

forEach 接受一个回调函数,你可以提前 <span style="font-size: 14px;">return</span>,相当于手写循环中的 <span style="font-size: 14px;">continue</span>。但是你不能 <span style="font-size: 14px;">break</span>——因为回调函数中没有循环让你去 <span style="font-size: 14px;">break</span>

<span style="font-size: 14px;">[1, 2, 3, 4, 5].forEach(x => {<br>  console.log(x);<br>  if (x === 3) {<br>    break;  // SyntaxError: Illegal break statement<br>  }<br>});<br></span>

解决方案还是有的。其他函数式编程语言例如 <span style="font-size: 14px;">scala</span> 就遇到了类似问题,它提供了一个函数
break,作用是抛出一个异常。

JavaScript 배열 연산의 기본

我们可以仿照这样的做法,来实现 <span style="font-size: 14px;">arr.forEach</span><span style="font-size: 14px;">break</span>

<span style="font-size: 14px;">try {<br>  [1, 2, 3, 4, 5].forEach(x => {<br>    console.log(x);<br>    if (x === 3) {<br>      throw 'break';<br>    }<br>  });<br>} catch (e) {<br>  if (e !== 'break') throw e; // 不要勿吞异常。。。<br>}<br></span>

恶心的一B对不对。还有其他方法,比如用 <span style="font-size: 14px;">Array.prototype.some</span> 代替 <span style="font-size: 14px;">Array.prototype.forEach</span>

考虑 Array.prototype.some 的特性,当 <span style="font-size: 14px;">some</span> 找到一个符合条件的值(回调函数返回 <span style="font-size: 14px;">true</span>)时会立即终止循环,利用这样的特性可以模拟 <span style="font-size: 14px;">break</span>Array.prototype.map

을 구분하지 못하는 경우가 많습니다. 및 🎜Array.prototype.forEach🎜 🎜의 실제 의미입니다. 🎜🎜🎜🎜map🎜🎜은 중국어로 🎜🎜map🎜🎜이라고 하는데, 시퀀스에 함수를 순차적으로 실행하여 또 다른 새로운 시퀀스를 파생시키는 것입니다. 이 함수는 일반적으로 부작용이 없으며 원래 배열(소위 순수 함수)을 수정하지 않습니다. 🎜🎜🎜🎜forEach🎜🎜 설명이 많지는 않지만 단순히 배열의 모든 항목을 특정 기능으로 처리합니다. 🎜🎜forEach🎜🎜에는 반환 값이 없으므로(정의되지 않은 반환) 해당 콜백 함수에는 일반적으로 부작용이 있습니다. 그렇지 않으면 이 🎜🎜forEach🎜🎜는 쓸모가 없습니다. 🎜🎜🎜🎜은 실제로 🎜🎜map🎜🎜이 🎜🎜forEach🎜🎜보다 강력하지만 🎜🎜map🎜🎜은 새로운 배열, 메모리 점유. 🎜🎜map🎜🎜의 반환 값을 사용하지 않는 경우 🎜🎜forEach🎜🎜🎜🎜Supplement: forEach 및 break🎜🎜🎜🎜를 사용해야 합니다. ES6 이전에는 배열을 순회하는 두 가지 주요 방법이 있었습니다. 직접 작성한 루프는 아래 첨자로 반복하고 🎜🎜Array.prototype.forEach🎜🎜를 사용하는 것입니다. 전자는 다재다능하고 가장 효율적이지만 작성하기가 더 번거롭습니다. 배열의 값을 직접 얻을 수 없습니다. 🎜🎜🎜🎜저자는 개인적으로 후자를 좋아합니다. 첨자와 반복 값, 기능적 스타일을 직접 얻을 수 있습니다(FP는 불변 데이터 구조에 초점을 맞추고 forEach는 본질적으로 부작용이므로 FP No God의 형식)은 쓰기에 너무 신선했습니다. 하지만! 여러분 중 학생 중 누구든지 forEach가 시작되면 중지할 수 없다는 점을 알고 있는지 궁금합니다. . . 🎜🎜🎜🎜forEach는 미리 🎜🎜return🎜🎜할 수 있는 콜백 함수를 허용합니다. 이는 손으로 쓴 루프의 🎜🎜continue🎜🎜에 해당합니다. 하지만 🎜🎜break🎜🎜은 할 수 없습니다. 콜백 함수에 🎜🎜break🎜🎜을 수행할 수 있는 루프가 없기 때문입니다. 🎜🎜
<span style="font-size: 14px;">[1, 2, 3, 4, 5].some(x => {<br>  console.log(x);<br>  if (x === 3) {<br>    return true; // break<br>  }<br>  // return undefined; 相当于 false<br>});<br></span>
🎜🎜다음이 있습니다. 여전히 해결책입니다. 🎜🎜scala🎜🎜와 같은 다른 함수형 프로그래밍 언어에서도 비슷한 문제가 발생했습니다. 이 언어는 예외를 발생시키는 함수
를 제공합니다. 🎜🎜🎜🎜JavaScript 배열 연산의 기본🎜🎜🎜🎜이 접근 방식을 따라 달성할 수 있습니다 🎜 🎜arr.forEach🎜🎜 of 🎜🎜break🎜🎜: 🎜🎜
<span   style="max-width:90%">for (const x of [1, 2, 3, 4, 5]) {<br>  console.log(x);<br>  if (x === 3) {<br>    break;<br>  }<br>}<br></span>
🎜🎜역겨운 쌍. 🎜🎜Array.prototype.forEach🎜🎜 대신 🎜🎜Array.prototype.some🎜🎜을 사용하는 등의 다른 방법도 있습니다. 🎜🎜🎜🎜 🎜🎜some🎜🎜이 정규화된 값을 찾을 때 Array.prototype.some의 특성을 고려하세요(콜백 함수는 🎜🎜true🎜🎜를 반환함). 루프는 즉시 종료됩니다. 이 기능은 🎜🎜break🎜🎜을 시뮬레이션하는 데 사용할 수 있습니다. 🎜🎜
<span style="font-size: 14px;">[1, 2, 3, 4, 5].some(x => {<br>  console.log(x);<br>  if (x === 3) {<br>    return true; // break<br>  }<br>  // return undefined; 相当于 false<br>});<br></span>

<span style="font-size: 14px;">some</span> 的返回值被忽略掉了,它已经脱离了判断数组中是否有元素符合给出的条件这一原始的含义。

在 ES6 前,笔者主要使用该法(其实因为 Babel 代码膨胀的缘故,现在也偶尔使用),ES6 不一样了,我们有了 for...of。<span style="font-size: 14px;">for...of</span> 是真正的循环,可以 <span style="font-size: 14px;">break</span>

<span style="font-size: 14px;">for (const x of [1, 2, 3, 4, 5]) {<br>  console.log(x);<br>  if (x === 3) {<br>    break;<br>  }<br>}<br></span>

但是有个问题,<span style="font-size: 14px;">for...of</span> 似乎拿不到循环的下标。其实 JavaScript 语言制定者想到了这个问题,可以如下解决:

<span style="font-size: 14px;">for (const [index, value] of [1, 2, 3, 4, 5].entries()) {<br>  console.log(`arr[${index}] = ${value}`);<br>}<br></span>

Array.prototype.entries

<span style="font-size: 14px;">for...of</span><span style="font-size: 14px;">forEach</span> 的性能测试:https://jsperf.com/array-fore... Chrome 中 <span style="font-size: 14px;">for...of</span> 要快一些哦

위 내용은 JavaScript 배열 연산의 기본의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.