[javascript] JavaScript의 다른 함수 내에서 함수 정의

function foo(a) {
    if (/* Some condition */) {
        // perform task 1
        // perform task 3
    }
    else {
        // perform task 2
        // perform task 3
    }
}

위와 비슷한 구조의 기능이 있습니다. 작업 3 을 함수로 추상화하고 싶지만 bar()이 함수의 액세스를 범위 내로 만 제한하고 싶습니다 foo(a).

내가 원하는 것을 달성하기 위해 다음으로 변경하는 것이 옳습니까?

function foo(a) {
    function bar() {
        // Perform task 3
    }

    if (/* Some condition */) {
        // Perform task 1
        bar();
    }
    else {
        // Perform task 2
        bar();
    }
}

위의 내용이 맞으면 호출 bar()될 때마다 get 재정의 foo(a)됩니까? (여기서 CPU 리소스 낭비가 걱정됩니다.)



답변

네, 당신이 가지고있는 것이 옳습니다. 몇 가지 참고 사항 :

  • bar함수를 호출 할 때마다 생성 foo되지만 다음과 같습니다.
    • 최신 브라우저에서 이것은 매우 빠른 프로세스입니다. (일부 엔진은 코드 를 한 번만 컴파일 한 다음 매번 다른 컨텍스트로 해당 코드를 재사용 할 수 있습니다. 대부분의 경우 Google의 V8 엔진 (Chrome 및 기타)에서 수행합니다.)
    • 그리고 무엇을하는지에 따라 bar일부 엔진은이를 “인라인”하여 함수 호출을 완전히 제거 할 수 있다고 결정할 수 있습니다. V8이이 작업을 수행하며, 이것이 수행하는 유일한 엔진은 아닙니다. 당연히 코드의 동작을 변경하지 않는 경우에만이를 수행 할 수 있습니다.
  • bar매번 생성 되는 성능 영향 은 JavaScript 엔진마다 크게 다릅니다. bar사소한 경우 감지 할 수없는 것부터 매우 작은 것까지 다양합니다. foo(예를 들어 mousemove핸들러에서) 연속으로 수천 번 호출 하지 않는다면 걱정하지 않을 것입니다. 당신이 그렇더라도 느린 엔진에서 문제를 본 경우에만 걱정할 것입니다. 다음은 DOM 작업과 관련된 테스트 케이스 입니다. 이는 영향이 있음을 시사하지만 사소한 것입니다 (아마도 DOM에 의해 씻겨 나옴). 여기에 순수 계산하고 테스트 케이스의 어떤 쇼 훨씬 더 높은 영향을하지만, 솔직히 심지어 우리의 차이를 얘기 마이크로 무언가에 심지어 92 % 증가합니다 그 때문에 초 미세발생하는 시간은 여전히 ​​매우, 매우 빠릅니다. 실제 영향을보기 전까지는 걱정할 필요가 없습니다.
  • bar함수 내에서만 액세스 할 수 있으며 해당 함수 호출에 대한 모든 변수 및 인수에 액세스 할 수 있습니다. 이것은 매우 편리한 패턴을 만듭니다.
  • 함수 선언을 사용했기 때문에 선언 위치 (위쪽, 아래쪽 또는 중간)는 흐름 제어 문 내부가 아니라 함수의 최상위 수준에있는 한 중요하지 않습니다. 구문 오류), 단계별 코드의 첫 번째 줄이 실행되기 전에 정의됩니다.


답변

이것이 클로저의 목적입니다.

var foo = (function () {
  function bar() {
    // perform task 3
  };

  function innerfoo (a) {
    if (/* some cond */ ) {
      // perform task 1
      bar();
    }
    else {
      // perform task 2
      bar();
    }
  }
  return innerfoo;
})();

Innerfoo (클로저)는 bar에 대한 참조를 보유하며, 클로저를 생성하기 위해 한 번만 호출되는 익명 함수에서 innerfoo에 대한 참조 만 반환됩니다.

바는 외부에서이 방법으로 접근 할 수 없습니다.


답변

var foo = (function () {
    var bar = function () {
        // perform task 3
    }
    return function (a) {

        if (/*some condition*/) {
            // perform task 1
            bar();
        }
        else {
            // perform task 2
            bar();
        }
    };
}());

클로저는 bar()포함 된 범위를 유지하고 자체 실행 익명 함수에서 새 함수를 반환하면보다 가시적 인 범위를 foo(). 익명의 자체 실행 기능은 정확히 한 번만 실행되므로 bar()인스턴스 가 하나 뿐이며 모든 실행이 foo()이를 사용합니다.


답변

예, 잘 작동합니다.

내부 기능은 외부 기능을 입력 할 때마다 다시 생성되지 않지만 다시 할당됩니다.

이 코드를 테스트하는 경우 :

function test() {

    function demo() { alert('1'); }

    demo();
    demo = function() { alert('2'); };
    demo();

}

test();
test();

이 표시됩니다 1, 2, 1, 2,하지 1, 2, 2, 2.


답변

중첩 및 비 중첩 및 함수 표현식과 함수 선언을 테스트하기 위해 jsperf를 만들었는데 중첩 테스트 케이스가 비 중첩보다 20 배 더 빠르게 수행된다는 사실에 놀랐습니다. (나는 그 반대 또는 무시할만한 차이를 예상했습니다).

https://jsperf.com/nested-functions-vs-not-nested-2/1

이것은 Chrome 76, macOS에 있습니다.


답변