> 웹 프론트엔드 > JS 튜토리얼 > JavaScript의 for 루프에 대한 자세한 소개

JavaScript의 for 루프에 대한 자세한 소개

黄舟
풀어 주다: 2017-03-03 14:42:40
원래의
1088명이 탐색했습니다.

ECMAScript5(줄여서 ES5)에는 세 가지 종류의 for 루프가 있습니다. 즉,

  • Simple for 루프

  • for-in

  • forEach

2015년 6월에 출시된 ECMAScript6(줄여서 ES6)에는 새로운 루프가 추가되었습니다. is:

  • for-of

for 루프의 4가지 유형을 살펴보겠습니다.

간단한 for 루프

가장 일반적인 작성 방법을 살펴보겠습니다.

const arr = [1, 2, 3];
for(let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
로그인 후 복사

루프 중에 배열 길이가 변경되지 않으면 다음을 수행해야 합니다. 배열의 길이는 더 나은 효율성을 달성하기 위해 변수에 저장됩니다. 다음은 향상된 작성 방법입니다.

const arr = [1, 2, 3];
for(let i = 0, len = arr.length; i < len; i++) {
    console.log(arr[i]);
}
로그인 후 복사

for-in

일반적으로 for-in을 사용하여 사용할 수 있습니다. iterate over iterate 배열의 내용, 코드는 다음과 같습니다.

const arr = [1, 2, 3];
let index;
for(index in arr) {
    console.log("arr[" + index + "] = " + arr[index]);
}
로그인 후 복사

일반적인 상황에서 실행 결과는 다음과 같습니다.

arr[0] = 1
arr[1] = 2
arr[2] = 3
로그인 후 복사

그러나 이렇게 하면 문제가 자주 발생합니다.

for-in의 진실

for-in 루프는 배열의 인덱스가 아닌 객체의 속성을 순회합니다. 따라서 for-in으로 순회하는 객체는 배열에 국한되지 않고 객체도 순회할 수 있습니다. 예는 다음과 같습니다:

const person = {
    fname: "san",
    lname: "zhang",
    age: 99
};
let info;
for(info in person) {
    console.log("person[" + info + "] = " + person[info]);
}
로그인 후 복사

결과는 다음과 같습니다:

person[fname] = san
person[lname] = zhang
person[age] = 99
로그인 후 복사

for-in이 속성을 순회하는 순서는 결정되지 않습니다. 출력 결과의 순서는 객체의 속성 순서와 아무 관련이 없습니다. 또한 속성의 알파벳 순서나 다른 순서와도 관련이 없습니다.

배열의 진실

배열은 자바스크립트의 객체이고, 배열의 인덱스는 속성명이다. 실제로 Javascript의 "배열"은 다소 오해의 소지가 있습니다. Javascript의 배열은 대부분의 다른 언어의 배열과 다릅니다. 첫째, Javascript의 Array는 메모리에서 연속적이지 않습니다. 둘째, Array의 인덱스는 오프셋을 참조하지 않습니다. 실제로 Array의 인덱스는 Number형이 아닌 String형이다. arr[0]을 올바르게 사용할 수 있는 이유는 언어가 자동으로 Number 유형의 0을 String 유형의 "0"으로 변환할 수 있기 때문입니다. 따라서 Javascript에는 배열 인덱스가 없고 "0", "1" 등과 같은 속성만 있습니다. 흥미롭게도 모든 Array 객체에는 길이 속성이 있어 다른 언어의 배열처럼 동작합니다. 그런데 Array 객체를 순회할 때 길이 속성이 출력되지 않는 이유는 무엇입니까? for-in은 "열거 가능한 속성"에 대해서만 반복할 수 있고 length는 열거 불가능한 속성이며 실제로 Array 객체에는 열거 불가능한 다른 속성이 많이 있기 때문입니다.

이제 다시 for-in을 사용하여 배열을 순회하는 예제를 살펴보겠습니다.

const arr = [1, 2, 3];
arr.name = "Hello world";
let index;
for(index in arr) {
    console.log("arr[" + index + "] = " + arr[index]);
}
로그인 후 복사

연산 결과는 다음과 같습니다.

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[name] = Hello world
로그인 후 복사

for-in은 "인덱스"뿐만 아니라 개체의 모든 속성을 반복하기 때문에 for-in이 새로운 "name" 속성을 통해 반복되는 것을 볼 수 있습니다. 동시에 여기서 출력되는 인덱스 값, 즉 "0", "1", "2"는 속성으로 출력되기 때문에 Number 타입이 아닌 String 타입이라는 점에 유의해야 한다. , 인덱스가 아닙니다. 이는 Array 객체에 새 속성을 추가하지 않고 배열의 내용만 출력할 수 있다는 뜻인가요? 대답은 '아니요'입니다. for-in은 배열 자체의 속성뿐만 아니라 배열 프로토타입 체인의 열거 가능한 모든 속성도 탐색하기 때문입니다. 아래 예를 살펴보겠습니다.

Array.prototype.fatherName = "Father";
const arr = [1, 2, 3];
arr.name = "Hello world";
let index;
for(index in arr) {
    console.log("arr[" + index + "] = " + arr[index]);
}
로그인 후 복사

실행 결과는 다음과 같습니다.

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[name] = Hello world
arr[fatherName] = Father
로그인 후 복사

이를 작성하면 for-in이 배열의 요소를 순회하는 데 적합하지 않다는 것을 알 수 있습니다. 객체 생성의 원래 의도이기도 한 속성을 탐색합니다. 한 가지 예외, 즉 희소 배열이 있습니다. 다음 예를 고려하십시오.

let key;
const arr = [];
arr[0] = "a";
arr[100] = "b";
arr[10000] = "c";
for(key in arr) {
    if(arr.hasOwnProperty(key)  &&    
        /^0$|^[1-9]\d*$/.test(key) &&    
        key <= 4294967294               
        ) {
        console.log(arr[key]);
    }
}
로그인 후 복사

for-in은 기존 엔터티만 순회합니다. 위 예에서 for-in은 3회 순회합니다(순회 속성은 "0", "100" 및 "10000" 요소입니다. , 일반 for 루프는 10001번 순회합니다.) 따라서 올바르게 수행되는 한 for-in은 배열의 요소를 탐색하는 데 큰 역할을 할 수도 있습니다.

작업 중복을 피하기 위해 위의 코드를 래핑할 수 있습니다.

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && 
        /^0$|^[1-9]\d*$/.test(prop) && 
        prop <= 4294967294; // 2^32 - 2
}
로그인 후 복사

사용 예는 다음과 같습니다.

for (let key in arr) {
    if (arrayHasOwnIndex(arr, key)) {
        console.log(arr[key]);
    }
}
로그인 후 복사

for-in 성능

위에서 언급했듯이 각 반복 작업은 인스턴스 또는 프로토타입 속성도 검색합니다. for-in 루프의 각 반복은 더 많은 오버헤드를 생성하므로 일반적인 속도는 1입니다. 다른 유형의 루프. /7. 따라서 알 수 없는 속성 수를 가진 객체를 반복해야 하는 경우가 아니라면 for-in 루프를 사용하지 않는 것이 좋습니다. 제한된 수의 알려진 속성 목록을 탐색해야 하는 경우 다음 예와 같은 다른 루프를 사용하는 것이 더 빠릅니다.

const obj = {
    "prop1": "value1",
    "prop2": "value2"
};

const props = ["prop1", "prop2"];
for(let i = 0; i < props.length; i++) {
    console.log(obj[props[i]]);
}
로그인 후 복사

위 코드에서 객체의 속성은 배열에 저장됩니다. , 각 속성에 대한 for-in 검색과 비교하여 이 코드는 지정된 속성에만 초점을 맞춰 루프의 오버헤드와 시간을 절약합니다.

forEach

ES5에는 forEach 루프라는 새로운 루프가 도입되었습니다.

const arr = [1, 2, 3];
arr.forEach((data) => {
    console.log(data);
});
로그인 후 복사

작업 결과:

1
2
3
로그인 후 복사

forEach 메서드는 유효한 값이 포함된 배열의 각 항목, 삭제된 항목(delete 메서드 사용 등)에 대해 콜백 함수를 실행합니다. ) 또는 값이 할당된 적이 없는 경우 건너뜁니다(값이 정의되지 않거나 null인 항목 제외). 콜백 함수는 세 가지 매개변수로 순서대로 전달됩니다.

  • 数组当前项的值;

  • 数组当前项的索引;

  • 数组对象本身;

需要注意的是,forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。

const arr = [];
arr[0] = "a";
arr[3] = "b";
arr[10] = "c";
arr.name = "Hello world";
arr.forEach((data, index, array) => {
    console.log(data, index, array);
});
로그인 후 복사

运行结果:

a 0 ["a", 3: "b", 10: "c", name: "Hello world"]
b 3 ["a", 3: "b", 10: "c", name: "Hello world"]
c 10 ["a", 3: "b", 10: "c", name: "Hello world"]
로그인 후 복사

这里的 index 是 Number 类型,并且也不会像 for-in 一样遍历原型链上的属性。

所以,使用 forEach 时,我们不需要专门地声明 index 和遍历的元素,因为这些都作为回调函数的参数。

另外,forEach 将会遍历数组中的所有元素,但是 ES5 定义了一些其他有用的方法,下面是一部分:

  • every: 循环在第一次 return false 后返回

  • some: 循环在第一次 return true 后返回

  • filter: 返回一个新的数组,该数组内的元素满足回调函数

  • map: 将原数组中的元素处理后再返回

  • reduce: 对数组中的元素依次处理,将上次处理结果作为下次处理的输入,最后得到最终结果。

forEach 性能

首先感谢@papa pa的提醒,才发现我之前的理解有错误。

大家可以看 jsPerf ,在不同浏览器下测试的结果都是 forEach 的速度不如 for。如果大家把测试代码放在控制台的话,可能会得到不一样的结果,主要原因是控制台的执行环境与真实的代码执行环境有所区别。

for-of

先来看个例子:

const arr = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
for(let data of arr) {
    console.log(data);
}
로그인 후 복사

运行结果是:

a
b
c
로그인 후 복사

为什么要引进 for-of?

要回答这个问题,我们先来看看ES6之前的 3 种 for 循环有什么缺陷:

  • forEach 不能 break 和 return;

  • for-in 缺点更加明显,它不仅遍历数组中的元素,还会遍历自定义的属性,甚至原型链上的属性都被访问到。而且,遍历数组元素的顺序可能是随机的。

所以,鉴于以上种种缺陷,我们需要改进原先的 for 循环。但 ES6 不会破坏你已经写好的 JS 代码。目前,成千上万的 Web 网站依赖 for-in 循环,其中一些网站甚至将其用于数组遍历。如果想通过修正 for-in 循环增加数组遍历支持会让这一切变得更加混乱,因此,标准委员会在 ES6 中增加了一种新的循环语法来解决目前的问题,即 for-of 。

那 for-of 到底可以干什么呢?

  • 跟 forEach 相比,可以正确响应 break, continue, return。

  • for-of 循环不仅支持数组,还支持大多数类数组对象,例如 DOM nodelist 对象。

  • for-of 循环也支持字符串遍历,它将字符串视为一系列 Unicode 字符来进行遍历。

  • for-of 也支持 Map 和 Set (两者均为 ES6 中新增的类型)对象遍历。

总结一下,for-of 循环有以下几个特征:

  • 这是最简洁、最直接的遍历数组元素的语法。

  • 这个方法避开了 for-in 循环的所有缺陷。

  • 与 forEach 不同的是,它可以正确响应 break、continue 和 return 语句。

  • 其不仅可以遍历数组,还可以遍历类数组对象和其他可迭代对象。

但需要注意的是,for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用
for-in 循环(这也是它的本职工作)。

最后要说的是,ES6 引进的另一个方式也能实现遍历数组的值,那就是 Iterator。上个例子:

const arr = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
const iter = arr[Symbol.iterator]();

iter.next() // { value: &#39;a&#39;, done: false }
iter.next() // { value: &#39;b&#39;, done: false }
iter.next() // { value: &#39;c&#39;, done: false }
iter.next() // { value: undefined, done: true }
로그인 후 복사

不过,这个内容超出了本文的范围,而且 Iterator 要讲的也有很多,以后有时间专门写一篇文章介绍,欢迎关注。

 以上就是深入了解 JavaScript 中的 for 循环 的详细介绍 的内容,更多相关内容请关注PHP中文网(www.php.cn)!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿