자 바스 크 립 트 의 폐쇄 가 무엇 인지 깊이 이해 하 다.

머리말
이 글 을 보기 전에 이전 글 자 바스 크 립 트 실행 상하 문 깊이 이해JavaScript 역할 영역 깊이 이해 을 살 펴 보고 문맥 과 역할 영역 을 이해 하 는 것 이 폐쇄 를 이해 하 는 데 큰 도움 이 된다.
추억 이 필요 한 지식 포인트:
  • 작용 역 과 어법 작용 역, 작용 역 은 변 수 를 찾 는 규칙 이다.어법 작용 역 은 네가 코드 를 쓸 때 확정 되 었 다.JavaScript 은 품사 작용 도 메 인 을 바탕 으로 하 는 언어 로 변수 가 정의 하 는 위 치 를 통 해 변수의 역할 도 메 인 을 알 수 있다.
  • 역할 도 메 인 체인: 특정한 함수 가 처음으로 호출 될 때 실행 환경 과 해당 하 는 역할 도 메 인 체인 을 만 들 고 역할 도 메 인 체인 을 특수 한 내부 속성 [[Scope]] 에 부여 합 니 다.그 다음 에 this, arguments 와 다른 이름 의 매개 변수 값 을 사용 하여 함수 의 활동 대상 을 초기 화 합 니 다.그러나 역할 영역 에서 외부 함수 의 활동 대상 은 항상 두 번 째 에 있 고 외부 함수 의 외부 함수 의 활동 대상 은 세 번 째 에 있 으 며... 역할 영역 체인 종점 의 전체 집행 환경 까지.

  • 실제 면접 장면
  • A: 폐쇄 가 무엇 입 니까
  • B: 함수 foo 내부 에서 변수 a 를 발 표 했 습 니 다. 함수 외부 에 서 는 접근 할 수 없습니다. 패 킷 을 닫 으 면 함수 외부 에서 함수 내부 에 접근 할 수 있 는 변수
  • 입 니 다.
  • A: 어, 정확 하지 않 아. 그럼 가방 을 닫 는 게 무슨 용도 인지 말 해 봐
  • B:... 죄송합니다. 갑자기 생각 이 안 나 네요
  • A: 오늘 면접 은 여기까지 입 니 다. 나중에 알려 드 리 겠 습 니 다.

  • 폐쇄 적 인 차 이 는 면접 에서 반드시 물 어 봐 야 할 지식 이다. 몇 년 전에 실습 을 찾 으 러 나 왔 을 때 이것 을 물 었 던 것 을 기억 하 는데 지금 면접 을 보 러 나 갔 을 때 이것 을 계속 물 었 다.면접 뿐만 아니 라 코드 에서 도 흔 하기 때문에 공 부 를 잘 해 볼 필요 가 있다.
    폐쇄 는 무엇 입 니까?
    함수 가 있 는 품사 작용 도 메 인 을 기억 하고 방문 할 수 있 을 때 닫 힌 패키지 가 생 깁 니 다. 함수 가 현재 품사 작용 도 메 인 밖에서 실행 되 더 라 도.
    function foo() {
        var a = 1; // a      foo        
        function bar() { // bar        ,     
            console.log(a); //             
        }
        return bar();
    }
    foo(); // 1

    foo () 함수 에서 내부 변수 a 를 설 명 했 습 니 다. 함수 외부 에 서 는 접근 할 수 없습니다. bar () 함 수 는 foo () 함수 내부 의 함수 입 니 다. 이때 foo 내부 의 모든 부분 변 수 는 bar 에 대해 볼 수 있 고 반대로 안 됩 니 다. bar 내부 의 부분 변 수 는 foo 에 대해 보이 지 않 습 니 다.이것 이 바로 자바 스 크 립 트 특유 의 '역할 도 메 인 체인' 이다.
    function foo() {
        var a = 1; // a      foo        
        function bar() { // bar        ,     
            console.log(a); //             
        }
        return bar;
    }
    const myFoo = foo();
    myFoo();

    이 코드 는 위의 코드 운행 결과 와 완전히 일치 합 니 다. 그 중에서 다른 점 은 내부 함수 bar 가 실행 하기 전에 외부 함수 에서 되 돌아 오 는 것 입 니 다. foo() 실행 후 되 돌아 오 는 값 (즉 내부 bar 을 변수 myFoo 에 부여 하고 호출 myFoo() 합 니 다.실제 적 으로 서로 다른 식별 자 인용 을 통 해 내부 함수 bar() 를 호출 했 을 뿐이다.foo() 함수 가 실 행 된 후 정상 적 인 상황 foo() 의 내부 역할 영역 전체 가 폐기 되 어 사용 중인 메모리 가 회수 되 었 습 니 다. 그러나 현재 foo 의 내부 역할 영역 bar() 은 아직 사용 되 고 있 기 때문에 회수 되 지 않 습 니 다. bar ()여전히 개 역할 영역 에 대한 인용 을 가지 고 있 습 니 다. 이 인용 은 패 킷 이 라 고 합 니 다. 이 함 수 는 정 의 된 품사 역할 영역 이외 의 곳 에서 호출 됩 니 다. 패 킷 을 닫 으 면 함수 가 정 의 된 품사 역할 영역 에 계속 접근 할 수 있 습 니 다.
    한 마디 로 설명: 패 킷 을 닫 는 것 은 다른 함수 역할 영역 에 접근 할 수 있 는 변 수 를 말 합 니 다. 패 킷 을 만 드 는 가장 흔 한 방법 은 한 함수 내부 에 다른 함 수 를 만 드 는 것 입 니 다.
    흔히 볼 수 있 는 폐쇄 적 인 것들
    function foo(a) {
        setTimeout(function timer(){
            console.log(a)
        }, 1000)
    }
    foo(2);
    foo 실행 1000ms 후 내부 작용 역 은 사라 지지 않 습 니 다. timer 함 수 는 여전히 foo 작용 역 의 인용 을 보유 하고 있 습 니 다. timer 함 수 는 폐쇄 입 니 다.
    타이머, 이벤트 모니터, Ajax 요청, 크로스 창 통신, Web Workers 또는 다른 비동기 또는 동기 화 작업 에서 리 셋 함수 만 사용 하면 사실상 패 킷 을 닫 습 니 다.
    순환 과 폐쇄
    for(var i = 0; i < 5; i++) {
        setTimeout(() => {
            console.log(i);
        }, i * 1000);
    }

    위의 이 코드 는 1 초 간격 으로 각각 출력 0, 1, 2, 3, 4 할 것 으로 예상 되 지만 실제로는 순서대로 출력 5, 5, 5, 5, 5 합 니 다. 먼저 5 가 어디서 나 왔 는 지 설명 합 니 다. 이 순환 의 종료 조건 은 i 더 이상 < 5 이 아니 라 조건 이 처음 설립 되 었 을 때 i 의 값 5 이 므 로 출력 은 순환 이 끝 났 을 때 i 의 최종 값 을 보 여 줍 니 다.
    지연 함수 의 리 셋 은 순환 이 끝 날 때 만 실 행 됩 니 다. 사실 타이머 가 실 행 될 때 모든 교체 에서 실 행 됩 니 다 setTimeout(.., 0). 모든 리 셋 함 수 는 순환 이 끝 난 후에 실 행 됩 니 다. 따라서 매번 5 개 씩 출력 합 니 다.
    우리 의 기 대 는 모든 교체 가 실 행 될 때 자신 에 게 '포획' i 의 사본 을 주 는 것 입 니 다. 그러나 실제 작용 역 의 원리 에 따 르 면 순환 중의 다섯 가지 함 수 는 각자 의 교체 에서 각각 정의 되 지만 그들 은 모두 공 유 된 전체 작용 역 에 갇 혀 있 기 때문에 실제 적 으로 하나 i 만 있 습 니 다. 즉, 모든 함수 가 하 나 를 공유 하 는 것 입 니 다.i 의 인용.
    for(var i = 0; i < 5; i++) {
        (function(j){
            setTimeout(() => {
                console.log(j);
            }, j * 1000);
        })(i)
    }

    코드 를 이렇게 바 꾸 면 우리 가 원 하 는 방식 으로 작업 할 수 있 습 니 다. 이렇게 수정 한 후에 매번 교체 할 때마다 IIFE (즉시 함수 실행) 를 사용 합 니 다.모든 교체 에 새로운 역할 영역 을 생 성하 여 지연 함수 의 리 셋 을 새로운 역할 영역 으로 폐쇄 할 수 있 고 모든 교체 내부 에 정확 한 값 을 가 진 변 수 를 포함 하여 접근 할 수 있 습 니 다.
    for(let i = 0; i < 5; i++) {
        setTimeout(() => {
            console.log(i);
        }, i * 1000);
    }

    ES6 블록 급 역할 영역 을 사용 하 는 let 교체 var 도 우리 의 목적 을 달성 할 수 있 습 니 다.
    왜 항상 자 바스 크 립 트 에서 닫 힌 애플 리 케 이 션 에는 키워드 'return' 이 있 습 니까?자바 스 크 립 트 시 크 릿 가든 에 서 는 패 키 지 를 닫 는 것 이 자바 스 크 립 트 의 매우 중요 한 특성 이 라 고 설명 합 니 다. 이 는 현재 역할 영역 이 항상 외부 역할 영역 에 접근 할 수 있 는 변 수 를 의미 합 니 다. 함 수 는 자바 스 크 립 트 에서 유일 하 게 자신의 역할 영역 을 가 진 구조 이기 때문에 패 키 지 를 닫 는 생 성 은 함수 에 의존 합 니 다.
    주의해 야 할 점
    메모리 가 새 기 쉽 습 니 다. 패 킷 을 닫 으 면 함수 역할 도 메 인 을 포함 하기 때문에 다른 함수 보다 더 많은 메모 리 를 사용 할 수 있 습 니 다. 패 킷 을 지나치게 사용 하면 메모리 가 너무 많이 사용 되 므 로 패 킷 을 닫 는 것 을 조심해 야 합 니 다.
    this 에 대한 상황
    패 킷 클 로즈 드 에 사용 this 대상.
    this 대상 은 실행 할 때 함수 의 실행 환경 을 기반 으로 연결 되 어 있 습 니 다. 전역 함수 에서 this 는 window 를 가리 키 며 함수 가 특정한 대상 의 방법 으로 호출 될 때 this 는 이 대상 을 가리 키 지만 익명 함수 의 실행 환경 은 전역 적 이기 때문에 this 대상 은 보통 window 를 가리 킵 니 다. 이전 이 편 은
    한 글 이해 this, call, apply, bind 글 에서 도 this 를 전문 적 으로 말 했다.
    var name = 'The window';
    
    var object = {
        name: 'my Object',
        getName: function() {
            return function() {
                return this.name;
            }
        }
    }
    console.log(object.getName()()); // The window       
  • 위의 코드 는 전역 변수 name 을 만 들 었 고 name 속성 을 포함 하 는 대상 을 만 들 었 습 니 다. 이 대상 은 하나의 방법 getName() 도 포함 되 어 있 습 니 다. 익명 함 수 를 되 돌려 주 고 익명 함 수 는 다시 돌아 갑 니 다 this.name.
  • 함 수 를 되 돌려 주기 때문에 호출 getName 함 수 를 되 돌려 줍 니 다. 결 과 는 문자열 'The window', 즉 전역 name 변수의 값 을 되 돌려 줍 니 다.
  • 왜 익명 함 수 는 역할 영역 을 포함 하 는 this 대상 을 얻 지 못 했 습 니까? 각 함 수 는 호출 될 때 두 개의 특수 변 수 를 자동 으로 가 져 옵 니 다. object.getName()(), this 내부 함 수 는 이 두 변 수 를 검색 할 때 활동 대상 만 검색 하기 때문에 외부 함수 의 이 두 변 수 를 직접 방문 할 수 없습니다.
    그러나 외부 역할 영역 에 있 는 this 대상 을 폐쇄 적 으로 접근 할 수 있 는 변수 에 저장 하면 폐쇄 적 으로 이 대상 에 접근 할 수 있 습 니 다.
    var name = 'The window';
    
    var object = {
        name: 'my Object',
        getName: function() {
            var that = this; //  this       that  
            return function() {
                return that.name;
            }
        }
    }
    
    console.log(object.getName()()); // my Object

    위의 코드 에서 this 대상 에 게 arguments 변 수 를 할당 하 였 습 니 다. that 변 수 는 함수 에 포함 되 어 있 습 니 다. 실시 간 함수 가 돌아 온 후에 도 that 는 이 object 를 참조 하여 호출 that 은 "my Object" 로 돌아 갑 니 다.
    arguments 와 this 에 같은 문제 가 존재 합 니 다. 역할 영역 에 있 는 arguments 대상 에 접근 하려 면 이 대상 에 대한 인용 을 다른 패키지 가 접근 할 수 있 는 변수 에 저장 해 야 합 니 다.
    몇 가지 특수 한 상황 에서 this 의 값 은 의외로 변 할 수 있 습 니 다. 예 를 들 어 아래 코드 는 앞의 예 를 수정 한 결과 입 니 다.
    var name = 'The window';
    
    var object = {
        name: 'my Object',
        getName: function() {
            return this.name
        }
    }
    
    console.log(object.getName()); // my Object
    console.log((object.getName)()); // my Object
    console.log((object.getName = object.getName)()); // The window       
  • 첫 번 째 는 정상 적 인 호출, 인쇄 object.getName()()
  • 두 번 째 는 이 방법 을 호출 하기 전에 괄호 를 넣 는 것 입 니 다. 그러나 object. getName 과 같 기 때문에 인쇄 “my Object”
  • 세 번 째 는 할당 문 구 를 먼저 실행 한 다음 에 할당 을 호출 한 결과 입 니 다. 이 할당 표현 식 은 함수 자체 이기 때문에 이때 호출 합 니 다. "my Object"this 을 가리 키 고 인쇄 된 것 은 window
  • 입 니 다.
    폐쇄 가 무엇 인지 에 대해 서 는 대략 여기까지 만 말 하고 다음 글 은 폐쇄 적 인 응용 장면 을 이야기 할 것 이다.
    총결산
  • 패 킷 을 닫 는 것 은 다른 함수 역할 영역 에서 변 수 를 방문 할 권리 가 있 는 함 수 를 말 합 니 다.
  • 패 키 지 는 보통 내부 변 수 를 만 드 는 데 사용 되 는데 이 변 수 는 외부 에서 임의로 수정 되 지 않 고 지정 한 인 터 페 이 스 를 통 해 조작 할 수 있 습 니 다.
  • 레 퍼 런 스
  • 전단 면접 풀기 (80% 지원자 불합격 시리즈): 폐쇄 부터 말하자면
  • MDN - 폐쇄
  • 자 바스 크 립 트 클 로 징 배우 기 (클 로 저)
  • 가방 을 닫 고 자세히 설명 하 다.
  • 폐쇄 를 이해 하 다
  • 나 는 누군가가 나 에 게 이렇게 설명 할 때 까지 자 바스 크 립 트 를 이해 하지 못 했다.
  • 좋은 웹페이지 즐겨찾기