JavaScript 에서 변수 향상 과 함수 향상 에 대한 상세 한 설명

첫 번 째 글 에서 변수의 향상 을 언급 했 기 때문에 오늘 은 변수 향상 과 함수 향상 을 소개 합 니 다.이 지식 포 인 트 는 흔히 말 하 는 것 이 라 고 할 수 있 지만 그 중에서 일부 세부 적 인 부분 은 블 로 거들 이 이 기 회 를 빌려 잘 정리 하고 싶 어 한다.
오늘 은 주로 다음 과 같은 몇 가 지 를 소개 한다.
1.변수 증가
2.함수 향상
3.승진 은 왜 하 는가
4.최고의 실천
그럼 주제 에 들 어가 자.
1.변수 증가
보통 JS 엔진 은 정식 적 으로 실행 되 기 전에 사전 컴 파일 을 합 니 다.이 과정 에서 먼저 변수 성명 과 함수 성명 을 현재 역할 필드 의 맨 위로 올 린 다음 에 다음 처 리 를 합 니 다.(주:현재 유행 하 는 JS 엔진 은 대부분 소스 코드 를 컴 파일 했 습 니 다.엔진 이 다 르 기 때문에 컴 파일 형식 도 차이 가 있 을 수 있 습 니 다.우리 가 여기 서 말 하 는 사전 컴 파일 과 향상 은 추상 적 이 고 이해 하기 쉬 운 개념 입 니 다)
다음 코드 에서 우 리 는 함수 에서 변 수 를 설명 하 였 으 나 이 변 수 는 if 구문 블록 에 있 습 니 다.

function hoistVariable() {
  if (!foo) {
    var foo = 5;
  }
   console.log(foo); // 5
}hoistVariable();
코드 를 실행 하면 foo 의 값 이 5 라 는 것 을 알 수 있 습 니 다.초보 자 들 은 이에 대해 잘 이해 하지 못 할 수도 있 습 니 다.만약 에 외부 역할 영역 에 도 foo 변수 가 존재 한다 면 더욱 당 혹 스 럽 습 니 다.외부 역할 영역 에 있 는 foo 변 수 를 인쇄 하 는 것 이 아 닙 니까?정 답 은:아 닙 니 다.현재 역할 영역 에 이 변수 성명 이 존재 한다 면 어디서 설명 하 든 이 변 수 를 참조 할 때 현재 역할 영역 에서 찾 습 니 다.외부 역할 영역 에 가지 않 습 니 다.
그러면 인쇄 결과 에 대해 말하자면 이것 은 사전 컴 파일 메커니즘 을 언급 해 야 한다.한 번 의 사전 컴 파일 을 거 친 후에 위의 코드 논 리 는 다음 과 같다.

//      
function hoistVariable() {
  var foo;

  if (!foo) {
    foo = 5;
  }
  console.log(foo); // 5
}
hoistVariable();
예,엔진 은 변수 성명 을 함수 상단 으로 올 렸 습 니 다.초기 값 은 undefined 입 니 다.자 연 스 럽 게 if 구문 블록 이 실 행 됩 니 다.foo 변수 할당 값 은 5 이 고 아래 의 인쇄 는 예상 한 결과 입 니 다.
유사 한 것 은 다음 과 같은 예 가 있다.

var foo = 3;

function hoistVariable() {
  var foo = foo || 5;

  console.log(foo); // 5
}

hoistVariable();
foo||5 이 표현 식 의 결 과 는 3 이 아 닌 5 입 니 다.외부 역할 영역 에 foo 변수 가 있 지만 함수 내 에 서 는 인용 되 지 않 습 니 다.사전 컴 파일 된 코드 논 리 는 다음 과 같 기 때 문 입 니 다.

var foo = 3;

//      
function hoistVariable() {
  var foo;

  foo = foo || 5;

  console.log(foo); // 5
}

hoistVariable();
만약 에 현재 역할 영역 에서 여러 개의 동명 변 수 를 설명 한다 면 우리 의 추측 에 따 르 면 그들의 같은 식별 자 는 역할 영역 상단 으로 올 라 가 고 다른 부분 은 순서대로 실 행 됩 니 다.예 를 들 어 아래 의 코드 와 같 습 니 다.

function hoistVariable() {
  var foo = 3;
   {
    var foo = 5;
  }
   console.log(foo); // 5
}
 hoistVariable();
자 바스 크 립 트 는 블록 역할 영역 이 없고 전역 역할 영역 과 함수 역할 영역 만 있 기 때문에 사전 컴 파일 된 코드 논 리 는 다음 과 같 습 니 다.

//      
function hoistVariable() {
  var foo;

  foo = 3;
  
  {
    foo = 5;
  }

  console.log(foo); // 5
}

hoistVariable();
2.함수 향상
다음 코드 가 낯 설 지 않 고 실제 개발 에서 도 흔 하 다 고 믿 습 니 다.

function hoistFunction() {
  foo(); // output: I am hoisted

  function foo() {
    console.log('I am hoisted');
  }
}

hoistFunction();
왜 함수 가 성명 하기 전에 호출 할 수 있 고 변수 성명 과 달리 정확 한 결 과 를 얻 을 수 있 습 니까?사실은 엔진 은 함수 성명 을 현재 역할 필드 의 맨 위 까지 올 렸 습 니 다.사전 컴 파일 후의 코드 논 리 는 다음 과 같 습 니 다.

//      
function hoistFunction() {
  function foo() {
    console.log('I am hoisted');
  }

  foo(); // output: I am hoisted
}

hoistFunction();
비슷 한 것 은 같은 역할 영역 에 여러 개의 동명 함수 성명 이 존재 하면 뒤에 나타 나 는 것 은 앞의 함수 성명 을 덮어 씁 니 다.

function hoistFunction() {
  function foo() {
    console.log(1);
  }

  foo(); // output: 2

  function foo() {
    console.log(2);
  }
}

hoistFunction();
함수 에 대해 서 는 위의 함수 성명 을 사용 하 는 것 을 제외 하고 함수 표현 식 을 사용 합 니 다.다음은 함수 성명 과 함수 표현 식 의 대비 입 니 다.

//     
function foo() {
  console.log('function declaration');
}

//        
var foo = function() {
  console.log('anonymous function expression');
};

//        
var foo = function bar() {
  console.log('named function expression');
};
익명 함수 표현 식 을 볼 수 있 습 니 다.사실은 이름 이 없 는 함수 성명 의 값 을 변수 에 부여 한 것 이 고,구명 함수 표현 식 은 이름 이 있 는 함수 의 값 을 변수 에 부여 한 것 입 니 다.이 함수 이름 은 이 함수 내부 에서 만 사용 할 수 있 습 니 다.사실 함수 표현 식 은 변 수 를 통 해 접근 할 수 있 기 때문에 같은 효 과 를 올 리 는 변수 도 존재 합 니 다.
함수 가 함수 표현 식 을 만 났 을 때 어떤 결과 가 나 올 지 다음 코드 를 보 세 요.

function hoistFunction() {
  foo(); // 2

  var foo = function() {
    console.log(1);
  };

  foo(); // 1

  function foo() {
    console.log(2);
  }

  foo(); // 1
}

hoistFunction();
실행 한 후에 우 리 는 출력 결과 가 21,1 순 이 었 는데 왜 이런 결과 가 나 왔 을 까?
자바 스 크 립 트 의 함 수 는 1 등 시민 이기 때문에 함수 성명 의 우선 순위 가 가장 높 고 현재 역할 영역 맨 위로 올 라 가기 때문에 첫 번 째 호출 시 아래 에 정 의 된 함수 성명 을 실제 실행 한 다음 두 번 째 호출 시 앞의 함수 표현 식 이 이전 함수 성명 과 같 기 때문에 덮어 쓰 고 이후 호출 도 같은 결 과 를 인쇄 합 니 다.위의 과정 은 사전 컴 파일 을 거 친 후에 코드 논 리 는 다음 과 같다.

//      
function hoistFunction() {
  var foo;

  foo = function foo() {
    console.log(2);
  }

  foo(); // 2

  foo = function() {
    console.log(1);
  };

  foo(); // 1

  foo(); // 1
}

hoistFunction();
다음 함수 와 변수 가 이름 을 바 꿀 때 어떻게 실행 되 는 지 이해 하기 어렵 지 않 습 니 다.

var foo = 3;

function hoistFunction() {
  console.log(foo); // function foo() {}

  foo = 5;
  
  console.log(foo); // 5

  function foo() {}
}

hoistFunction();
console.log(foo);   // 3
함수 성명 이 역할 영역 맨 위로 올 라 간 다음 에 5 로 할당 되 었 고 외층 의 변 수 는 덮어 쓰 지 않 았 습 니 다.사전 컴 파일 을 거 친 후에 상기 코드 의 논 리 는 다음 과 같 습 니 다.

//      

var foo = 3;

function hoistFunction() {
  var foo;
  foo = function foo() {};
  console.log(foo); // function foo() {} 
  foo = 5;
  console.log(foo); // 5
}

hoistFunction();
console.log(foo);  // 3
따라서 함수 의 우선권 이 가장 높 습 니 다.이것 은 영원히 작용 역 의 맨 위로 올 라 간 다음 에 함수 표현 식 과 변수 가 순서대로 실 행 됩 니 다.이 점 을 명심 하 세 요.
3.승진 은 왜 하 는가
변수 향상 과 함수 향상 을 왜 하 는 지 에 대해 서 는 명확 한 답 이 없 었 지만 최근 에 읽 었 습 니 다Dmitry Soshnikov 의 이전 글 에서다소 알 게 되 었 습 니 다.다음은 Dmitry Soshnikov 의 초기 트 위 터 입 니 다.그 도 이 문제 에 관심 이 많 습 니 다.

그리고 Jeremy Ashkenas 는 Brendan Eich 에 게 이 이 야 기 를 나 누고 싶 어 합 니 다.

마지막 으로 Brendan Eich 는 답 을 내 놓 았 다.

대체적으로 1 세대 JS 가상 컴퓨터 의 추상 적 인 오류 로 인해 컴 파일 러 는 변 수 를 스 택 슬롯 에 넣 고 색인 을 작성 한 다음 에(현재 역할 필드 의)입구 에서 변 수 를 스 택 슬롯 안의 변수 에 연결 시 켰 다 는 뜻 이다.주:여기 서 언급 한 추상 은 컴퓨터 용어 로 내부 에서 발생 하 는 더욱 복잡 한 일 에 대한 간소화 이다.)
그 다음 에 Dmitry Soshnikov 는 함수 향상 을 언급 했다.그 는 서로 재 귀(즉,A 함수 에서 B 함수 로 호출 되 고 B 함수 도 A 함수 로 호출 된다)를 언급 했다.

그리고 Brendan Eich 는 열심히 답 을 내 놓 았 습 니 다.

Brendan Eich 는 함수 향상 은 서로 재 귀 하 는 문 제 를 해결 하기 위 한 것 이 고 대체적으로 ML 언어 와 같은 아래 에서 위로 의 순서 문 제 를 해결 할 수 있다 고 확신 했다.
여기 서 서로 재 귀 하 는 것 을 간단하게 논술 하고 다음 두 함 수 는 각각 자신의 함수 에서 상대방 을 호출 했다.

//     
function isEven(n) {
  if (n === 0) {
    return true;
  }
  return isOdd(n - 1);
}

console.log(isEven(2)); // true

//     
function isOdd(n) {
  if (n === 0) {
    return false;
  }
  return isEven(n - 1);
}
함수 가 올 라 가지 않 고 아래 에서 위로 올 라 가 는 순서 로 isEven 함수 가 호출 되 었 을 때 isOdd 함수 가 설명 되 지 않 았 기 때문에 isEven 내부 에서 isOdd 함 수 를 호출 할 수 없습니다.그래서 Brendan Eich 는 함수 향상 이라는 형식 을 디자인 하여 함 수 를 현재 역할 영역의 맨 위로 올 렸 습 니 다.

//     
function isEven(n) {
  if (n === 0) {
    return true;
  }
  return isOdd(n - 1);
}

//     
function isOdd(n) {
  if (n === 0) {
    return false;
  }
  return isEven(n - 1);
}

console.log(isEven(2)); // true
이렇게 되면 문 제 는 쉽게 풀 릴 것 이다.
마지막 으로 Brendan Eich 는 변수 향상 과 함수 향상 에 대해 서도 정 리 를 했다.

아마도 변수 향상 은 인위적인 문제 이 고 함수 향상 은 처음에 디자인 할 때 목적 이 있 었 다.
이로써 변수 향상 과 함수 향상 에 대해 서 는 그 진실 을 알 고 있 을 것 이 라 고 믿 습 니 다.
4.최고의 실천
변수 향상 과 함수 향상 을 이해 하면 우 리 는 이 언어 를 더욱 잘 이해 하고 잘 제어 할 수 있 습 니 다.그러나 개발 에서 우 리 는 이런 기 교 를 사용 하지 말고 우리 의 코드 를 규범화 시 켜 가 독성 과 유지 가능성 을 가 져 야 합 니 다.
구체 적 인 방법 은 변수 든 함수 든 먼저 설명 한 후에 사용 해 야 한 다 는 것 이다.다음은 간단 한 예 를 들 었 다.

var name = 'Scott';
var sayHello = function(guest) {
  console.log(name, 'says hello to', guest);
};

var i;
var guest;
var guests = ['John', 'Tom', 'Jack'];

for (i = 0; i < guests.length; i++) {
  guest = guests[i];
  
  // do something on guest

  sayHello(guest);
}
새로운 프로젝트 에 대해 서 는 let 로 var 를 교체 할 수 있 습 니 다.더 신뢰 할 수 있 고 유지 가능성 이 높 습 니 다.
let name = 'Scott';let sayHello = function(guest) { console.log(name, 'says hello to', guest);};let guests = ['John', 'Tom', 'Jack'];for (let i = 0; i < guests.length; i++) { let guest = guests[i]; // do something on guest sayHello(guest);}
특히 ES6 의 클 라 스 성명 도 향상 되 었 으 나 let,const 와 마찬가지 로 제약 과 제한 을 받 았 다.그 규정 은 위 치 를 다시 밝 히 기 전에 인용 하면 비합법적 이 고 이상 을 던 질 것 이다.
따라서 초기 코드 든 ES6 의 코드 든 우 리 는 한 가 지 를 따 르 고 먼저 설명 한 다음 에 사용 해 야 한다.
본문 이 끝나다.
참고 자료:
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
http://dmitrysoshnikov.com/notes/note-4-two-words-about-hoisting/
https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
http://stackoverflow.com/questions/7506844/javascript-function-scoping-and-hoisting
자 바스 크 립 트 의 변수 향상 과 함수 향상 에 관 한 상세 한 설명 은 여기까지 입 니 다.자 바스 크 립 트 변수 향상 과 함수 향상 에 관 한 더 많은 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 지원 바 랍 니 다!

좋은 웹페이지 즐겨찾기