루프 대신 순회 방법을 사용하는 것을 선호하세요
루프를 사용하면 DRY(Don't Repeat Yourself) 원칙을 위반하기 쉽습니다. 순환문의 단락을 손으로 쓰는 것을 피하기 위해 일반적으로 복사-붙여넣기 방법을 선택하기 때문입니다. 그러나 그렇게 하면 코드에 중복된 코드가 많이 생기고 개발자는 무의미하게 "바퀴를 재발명"하게 됩니다. 더 중요한 것은 복사하여 붙여넣을 때 시작 인덱스 값, 종료 조건 등과 같은 루프의 세부 사항을 간과하기 쉽다는 것입니다.
예를 들어, n이 컬렉션 개체의 길이라고 가정할 때 다음 for 루프에는 이 문제가 있습니다.
for (var i = 0; i <= n; i++) { ... } // 终止条件错误,应该是i < n for (var i = 1; i < n; i++) { ... } // 起始变量错误,应该是i = 0 for (var i = n; i >= 0; i--) { ... } // 起始变量错误,应该是i = n - 1 for (var i = n - 1; i > 0; i--) { ... } // 终止条件错误,应该是i >= 0
루프의 일부 세부 사항에서 실수하기 쉽다는 것을 알 수 있습니다. JavaScript에서 제공하는 클로저(항목 11 참조)를 사용하면 재사용을 위해 루프의 세부 정보를 캡슐화할 수 있습니다. 실제로 ES5는 이 문제를 해결할 수 있는 몇 가지 방법을 제공합니다. 그 중 Array.prototype.forEach가 가장 간단한 것입니다. 이를 사용하여 다음과 같은 루프를 작성할 수 있습니다.
// 使用for循环 for (var i = 0, n = players.length; i < n; i++) { players[i].score++; } // 使用forEach players.forEach(function(p) { p.score++; });
컬렉션 개체를 순회하는 것 외에도 또 다른 일반적인 패턴은 원본 컬렉션의 각 요소에 대해 일부 작업을 수행한 다음 새 컬렉션을 가져오는 것입니다. 또한 forEach 메서드를 사용하여 다음을 구현합니다.
// 使用for循环 var trimmed = []; for (var i = 0, n = input.length; i < n; i++) { trimmed.push(input[i].trim()); } // 使用forEach var trimmed = []; input.forEach(function(s) { trimmed.push(s.trim()); });
그러나 한 컬렉션을 다른 컬렉션으로 변환하는 이 패턴은 매우 일반적이므로 ES5는 코드를 더욱 단순하고 우아하게 만들기 위해 Array.prototype.map 메서드도 제공합니다.
var trimmed = input.map(function(s) { return s.trim(); });
또한 특정 조건에 따라 컬렉션을 필터링한 다음 원본 컬렉션의 하위 집합을 얻는 또 다른 공통 모드가 있습니다. 이 모드를 구현하기 위해 ES5에서는 Array.prototype.filter가 제공됩니다. 이 메서드는 true 또는 false를 반환하는 함수인 조건자를 매개 변수로 받아들입니다. true를 반환하면 해당 요소가 새 컬렉션에 유지된다는 의미이고, false를 반환하면 해당 요소가 새 컬렉션에 표시되지 않는다는 의미입니다. 예를 들어, 다음 코드를 사용하여 제품 가격을 필터링하고 가격이 [min, max] 범위에 있는 제품만 유지합니다.
listings.filter(function(listing) { return listing.price >= min && listing.price <= max; });
물론 위 방법은 ES5를 지원하는 환경에서 사용 가능합니다. 다른 환경에는 두 가지 옵션이 있습니다. 1. 개체와 컬렉션을 작동하는 몇 가지 일반적인 방법을 제공하는 밑줄 또는 lodash와 같은 타사 라이브러리를 사용합니다. 2. 필요에 따라 정의하십시오.
예를 들어 특정 조건에 따라 컬렉션의 처음 여러 요소를 가져오는 다음 메서드를 정의합니다.
function takeWhile(a, pred) { var result = []; for (var i = 0, n = a.length; i < n; i++) { if (!pred(a[i], i)) { break; } result[i] = a[i]; } return result; } var prefix = takeWhile([1, 2, 4, 8, 16, 32], function(n) { return n < 10; }); // [1, 2, 4, 8]
이 메서드를 더 잘 재사용하려면 Array.prototype 개체에서 정의할 수 있습니다. 특정 영향 항목 42를 참조하십시오.
Array.prototype.takeWhile = function(pred) { var result = []; for (var i = 0, n = this.length; i < n; i++) { if (!pred(this[i], i)) { break; } result[i] = this[i]; } return result; }; var prefix = [1, 2, 4, 8, 16, 32].takeWhile(function(n) { return n < 10; }); // [1, 2, 4, 8]
순회 기능을 사용하는 것보다 루프를 사용하는 것이 더 나은 경우는 단 한 번뿐입니다. 중단 및 계속을 사용해야 하는 경우입니다. 예를 들어 forEach를 사용하여 위의 takeWhile 메서드를 구현하는 경우 문제가 발생합니다. 조건자가 충족되지 않으면 어떻게 구현해야 할까요?
function takeWhile(a, pred) { var result = []; a.forEach(function(x, i) { if (!pred(x)) { // ? } result[i] = x; }); return result; }
내부 예외를 사용하여 판단할 수 있지만 이는 약간 서투르고 비효율적이기도 합니다.
function takeWhile(a, pred) { var result = []; var earlyExit = {}; // unique value signaling loop break try { a.forEach(function(x, i) { if (!pred(x)) { throw earlyExit; } result[i] = x; }); } catch (e) { if (e !== earlyExit) { // only catch earlyExit throw e; } } return result; }
하지만 forEach를 사용한 후에는 사용하기 전보다 코드가 훨씬 더 장황해집니다. 이것은 분명히 문제가 있습니다. 이 문제에 대해 ES5는 루프의 조기 종료를 처리하는 일부 및 모든 방법을 제공합니다. 사용법은 다음과 같습니다:
[1, 10, 100].some(function(x) { return x > 5; }); // true [1, 10, 100].some(function(x) { return x < 0; }); // false [1, 2, 3, 4, 5].every(function(x) { return x > 0; }); // true [1, 2, 3, 4, 5].every(function(x) { return x < 3; }); // false
이 두 가지 방법은 단락(Short-circuiting) 방법입니다. 어떤 요소가 some 메서드의 조건자에서 true를 반환하면 some 메서드가 false를 반환하는 한 모든 메서드도 false를 반환합니다.
따라서 takeWhile은 다음과 같이 구현할 수 있습니다.
function takeWhile(a, pred) { var result = []; a.every(function(x, i) { if (!pred(x)) { return false; // break } result[i] = x; return true; // continue }); return result; }
사실 이게 함수형 프로그래밍의 아이디어입니다. 함수형 프로그래밍에서는 명시적인 for 루프나 while 루프를 거의 볼 수 없습니다. 루프의 세부 사항은 훌륭하게 캡슐화되어 있습니다.
위 내용은 JavaScript에서 루프 코드보다 순회 방법이 선호되는 이유에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!