어레이의 "모든"또는 "일부"의 부작용은 나쁜가요?


9

나는 항상 부작용 if이 나쁜 상태 라는 것을 배웠습니다 . 내가 말하고 싶은 건;

if (conditionThenHandle()) {
    // do effectively nothing
}

... 반대로;

if (condition()) {
    handle();
}

... 그리고 나는 그것을 이해하지 못하기 때문에 동료들도 행복하다는 것을 알고 있습니다. 우리는 금요일 오후 7시에 집에 돌아가고 모두 즐거운 주말을 보냅니다.

이제 ECMAScript5는 every()and some()to 와 같은 메소드를 도입 Array했으며 매우 유용합니다. 그것들은의 것보다 깨끗 하고for (;;;) 다른 범위를 제공 하며 변수가 요소에 액세스 할 수있게합니다.

입력의 유효성을 검사 할 때 그러나, 나는 더 종종보다하지 이용하여 자신을 찾을 수 있습니다 every/ some다음 입력을 검증 사용 조건에 every/ some 다시 사용 가능한 모델에 입력을 변환하는 몸에;

if (input.every(function (that) {
    return typeof that === "number";
})) {
    input.every(function (that) {
        // Model.findById(that); etc
    }
} else {
    return;
}

... 내가 하고 싶은 일이 있을 때 ;

if (!input.every(function (that) {
    var res = typeof that === "number";

    if (res) {
        // Model.findById(that); etc.
    }

    return res;
})) {
    return;
}

...이 if조건 에서 나에게 부작용을줍니다 .

이와 비교해 볼 때 이것은 코드가 이전 코드로 보일 것입니다 for (;;;).

for (var i=0;i<input.length;i++) {
    var curr = input[i];

    if (typeof curr === "number") {
        return;
    }

    // Model.findById(curr); etc.
}

내 질문은 :

  1. 이것은 확실히 나쁜 습관입니까?
  2. 암 I (MIS | AB)를 사용 some하고 every( 해야 나는를 사용 for(;;;)이를 위해?)
  3. 더 나은 접근 방법이 있습니까?

3
필터링, 매핑 및 축소뿐만 아니라 모든 쿼리는 쿼리이므로 악용 될 경우 부작용이 없습니다.
Benjamin Gruenbaum

@ BenjaminGruenbaum : 그래서 그것들이 더 자주 이빨을 만들지 않습니까? 내가 사용하는 경우 9/10, some내가하고 싶은 일을 내가 사용하는 경우, 요소와 함께 every, 내가 그 모든 요소에 뭔가를 ... 싶어 some하고 every그래서 하나 난 못해, 내가 그 정보에 액세스 할 수 없습니다 그것들을 사용 하거나 부작용을 추가해야합니다.
Isaac

아닙니다. 부작용을 언급 할 때 나는 몸이 아니라면 머리 안쪽을 의미합니다. 신체 내부에서 원하는 방식으로 수정할 수 있습니다. 일부 / 언제나 전달할 콜백 내부의 객체를 변경하지 마십시오.
Benjamin Gruenbaum

@ BenjaminGruenbaum : 그러나 그것은 정확히 내 요점입니다. 내가 사용하는 경우 some내에서 if배열의 특정 요소가 내가 운영 할 필요가 특정 자산, 9/10 전시 여부를 결정하는 조건 내에서 해당 요소 if몸을; 지금과 같은 some말하지 않는 (그냥 "하나했다") 속성을 전시 요소, 나도 사용할 수 있습니다 some 다시 (O (2N)), 몸에 또는 난 그냥 내에서 작업을 수행 할 수있는 경우 (조건 머리에 부작용이 있기 때문에 나쁘다).
Isaac

... 물론 동일하게 적용됩니다 every.
Isaac

답변:


9

내가 제대로 요점을 이해한다면, 당신은 잘못-사용하거나 남용하는 것 같다 everysome하지만 당신이 직접 배열의 요소를 변경하고자하는 경우는 거의 피할 수있다. 내가 틀렸다면 정정하십시오. 그러나 당신이하려는 것은 시퀀스의 일부 또는 모든 요소가 특정 조건을 나타내는 지 확인한 다음 해당 요소를 수정하는 것입니다. 또한 코드는 술어를 통과하지 않는 항목을 찾을 때까지 모든 항목에 무언가를 적용하는 것으로 보이며 그게 당신이하는 일이라고 생각하지 않습니다. 어쨌든

첫 번째 예를 보자 (약간 수정)

if (input.every(function (that) {
    return typeof that === "number";
})) {
    input.every(function (that) {
        that.foo();
    }
} else {
    return;
}

당신이하고있는 일은 실제로 일부 / 모든 /지도 / 감소 / 필터 / 기타 개념의 정신에 약간의 영향을 미칩니다. Every특정 항목을 준수하는 모든 항목에 영향을주기 위해 사용되는 것이 아니라 컬렉션의 모든 항목이 작동하는지 알려주기 위해 사용해야합니다. 술어가 true로 평가되는 모든 항목에 함수를 적용하려는 경우이를 수행하는 "좋은"방법은

var filtered = array.filter(function(item) {
    return typeof item === "number";
});

var mapped = filtered.map(function(item) {
    return item.foo(); //provided foo() has no side effects and returns a new object of item's type instead.  See note about foreach below.
});

또는 foreach맵 대신을 사용 하여 항목을 제자리에서 수정할 수 있습니다 .

some기본적으로 동일한 논리가에 적용됩니다 .

  • every배열의 모든 요소가 테스트를 통과하는지 테스트 하는 데 사용 합니다.
  • some배열에서 하나 이상의 요소가 테스트를 통과하는지 테스트 하는 데 사용 합니다.
  • map입력 배열의 모든 요소에 대해 1 개의 요소 (선택한 함수의 결과)가 포함 된 새 배열을 반환하는 데 사용 합니다.
  • 당신은 사용 filter길이가 0 <배열 반환하는 length< initial array length요소, 제공된 술어 시험을 통과 원래 배열에 포함 된 모든 모든을.
  • foreach지도를 원하지만 제자리에 사용 하려는 경우에 사용
  • reduce배열 결과를 단일 객체 결과 (배열 일 수는 있지만 반드시 필요하지는 않음)로 결합하려는 경우에 사용 합니다.

그것들을 많이 사용할수록 (그리고 LISP 코드를 많이 쓸수록), 그것들이 어떻게 관련되어 있는지, 다른 것들과 에뮬레이트 / 구현하는 방법을 더 많이 깨닫게됩니다. 이 쿼리에서 강력하고 흥미로운 점은 의미론과 코드에서 유해한 부작용을 제거하기 위해 실제로 어떻게 추진하는지입니다.

편집 (의견에 비추어) : 모든 요소가 객체인지 확인하고 모두 유효한 경우 응용 프로그램 모델로 변환하려고한다고 가정 해 봅시다. 단일 패스로이를 수행하는 한 가지 방법은 다음과 같습니다.

var dirty = false;
var app_domain_objects = input.map(function(item) {
    if(validate(item)) {
        return new Model(item);
    } else {
        dirty = true; //dirty is captured by the function passed to map, but you know that :)
    }
});
if(dirty) {
    //your validation test failed, do w/e you need to
} else {
    //You can use app_domain_objects
}

이 방법으로 객체가 유효성 검사를 통과하지 않아도 전체 배열을 계속 반복하면을 사용하여 유효성 검사하는 것보다 느립니다 every. 그러나 대부분의 경우 배열이 유효하거나 (그렇기를 바랍니다) 대부분의 경우 배열에 대한 단일 패스를 수행하고 사용 가능한 Application Model 개체 배열로 끝납니다. 의미론이 존중되고 부작용을 피하며 모든 사람이 행복해질 것입니다!

foreach와 비슷한 자체 쿼리를 작성하여 배열의 모든 멤버에 함수를 적용하고 조건 자 테스트를 모두 통과하면 true / false를 반환합니다. 다음과 같은 것 :

function apply_to_every(arr, predicate, func) {
    var passed = true;
    for(var i = 0; i < array.length; ++i) {
        if(predicate(arr[i])) {
            func(arr[i]);
        } else {
            passed = false;
            break;
        }
    }
    return passed;
}

그래도 배열이 수정됩니다.

이것이 도움이되기를 바랍니다. 쓰기가 매우 즐거웠습니다. 건배!


답변 주셔서 감사합니다. 나는 반드시 요소를 수정하려고하고 있지 않다 장소에서 당 자체; 내 실제 코드에서, 나는 내가 먼저 해요, 그래서 객체의 JSON 형식의 배열을 받고있어 확인하는 입력을 if (input.every()), 각 요소가 있는지 확인하는 것입니다 (객체 typeof el === "object && el !== null, 등) 한 후 검증합니다, 나는에 각 요소를 변환 할 경우 각각의 응용 모델 (이제 여러분은 map()내가 사용할 수 있다고 언급 input.map(function (el) { return new Model(el); });했지만 반드시 그럴 필요 없습니다 .
Isaac

.. 그러나 map()배열을 두 번 반복 해야한다는 것을 알 수 있습니다 . 한 번은 유효성을 검사하고 다른 하나는 변환합니다. 그러나, 표준 사용하여 for(;;;)루프를,이 사용하여 하나 반복 할 수있는,하지만 난에 적용하는 방법을 찾을 수없는 every, some, map또는 filter단지이 시나리오에서, 그리고 수행 바람직하지 않은 측면 효과를 가진하거나 bad-을 도입하지 않고, 패스를 연습.
Isaac

@Isaac 좋아, 늦게 미안해, 나는 지금 당신의 상황을 더 명확하게 이해합니다. 물건을 추가하기 위해 답변을 편집하겠습니다.
pwny

큰 답변에 감사드립니다. 정말 도움이되었습니다 :).
Isaac

-1

부작용은 if 조건이 아니며 if의 본문에 있습니다. 실제 조건에서 해당 본문을 실행할지 여부 만 결정했습니다. 당신의 접근 방식에는 아무런 문제가 없습니다.


안녕, 답변 주셔서 감사합니다. 미안하지만 중 나는 당신의 대답을 오해 한, 또는 당신은 코드를 잘못 해석했습니다 ... 내 코드에서 모든 것이 내 if단지로, 조건을 return내부에 존재 if몸의 '; 분명히 내가 "덧붙일 코드 샘플에 대해서 이야기하고 무엇을하고 싶은 것은, ...
이삭

1
죄송합니다, @Issac의 부작용은 실제로 if상태입니다.
로스 패터슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.