Js 의 폐쇄 와 this

10475 단어 자바 script
이 문 제 를 이해 하려 면 먼저 하나의 개념 을 분명히 해 야 한다. 실행 문맥
상하 문 을 실행 하 는 것 은 무엇 입 니까?
실행 가능 한 코드 를 실행 할 때 실행 가능 한 컨 텍스트 를 만 듭 니 다.그의 구성 은 다음 과 같다.
executionContextObj = {
    this:           this,
    VO:    ,
    scopeChain:     ,     
}

JS 는 단일 스 레 드 이기 때문에 한 번 에 한 가지 일 만 발생 할 수 있 고 다른 일 은 지정 한 컨 텍스트 스 택 에 놓 여 줄 을 서 있 습 니 다.
js 해석 기 는 실행 코드 를 초기 화 할 때 전체 실행 컨 텍스트 를 스 택 에 만 듭 니 다. 이 어 함수 호출 에 따라 새로운 실행 컨 텍스트 스 택 을 만 들 고 누 릅 니 다.함수 가 실 행 된 후 이 실행 컨 텍스트 가 팝 업 됩 니 다.
다섯 가지 관건:
  • 단일 스 레 드
  • 동기 화 실행
  • 전체 문맥
  • 무제 한 함수 상하 문
  • 매번 함수 호출 시 새로운 컨 텍스트 를 만 듭 니 다. 자신 을 호출 하 는 것 을 포함 합 니 다
  • 상하 문 에 세 워 진 보 주 를 실행 하 다
    \ # \ # 창설 단계
    초기 화 역할 도 메 인 체인 생 성 변수 대상 생 성 arguments 스 캔 함수 성명 스 캔 변수 성명 this
    실행 단계
    변수 와 함 수 를 초기 화 하 는 참조 실행 코드 this 는 함수 가 실 행 될 때 this 는 항상 이 함 수 를 호출 하 는 대상 을 가리킨다.this 의 지향 을 판단 하려 면 사실은 this 가 있 는 함수 가 누구 에 속 하 는 지 판단 하 는 것 이다.
    호출 대상 가리 키 기:
    function foo() {
        console.log( this.a );
    }
    var obj = {
        a: 2,
        foo: foo
    };
    obj.foo(); // 2
    //       
    
    function foo() {
        console.log( this.a );
    }
    var a = 2;
    foo(); // 2
    //   
    
    //  
    var bar = foo
    a = 3
    bar() // 3  2
    

    / / 이 예 를 통 해 this 가 함수 호출 일 때 확인 되 는 것 임 을 더욱 잘 알 수 있 습 니 다.
    / / 더 감아 주세요
    function foo() {
        console.log( this.a );
    }
    function doFoo(fn) {
        this.a = 4
        fn();
    }
    var obj = {
        a: 2,
        foo: foo
    };
    var a =3
    doFoo( obj.foo ); // 4
    //  
    
    function foo() {
        this.a = 1
        console.log( this.a );
    }
    function doFoo(fn) {
        this.a = 4
        fn();
    }
    var obj = {
        a: 2,
        foo: foo
    };
    var a =3
    doFoo( obj.foo ); // 1
    

    왜 그 럴 까요?foo 에 설 치 된 a, 유사 한 역할 영역 원 리 를 우선 읽 기 때 문 입 니까?
    foo 와 doFoo 의 this 를 인쇄 함으로써 그들의 this 는 모두 window 를 가리 키 고 그들의 조작 은 window 의 a 값 을 수정 한 다 는 것 을 알 수 있 습 니 다.foo 에 설 치 된 a 를 우선 읽 는 것 이 아 닙 니 다.
    그래서 코드 를 바 꾸 면
    function foo() {
        setTimeout(() => this.a = 1,0)
        console.log( this.a );
    }
    function doFoo(fn) {
        this.a = 4
        fn();
    }
    var obj = {
        a: 2,
        foo: foo
    };
    var a =3
    doFoo( obj.foo ); // 4
    setTimeout(obj.foo,0) // 1
    

    위의 코드 결 과 는 우리 의 추측 을 증명 할 수 있다.
    new 구조 로 새로운 대상 을 가리 키 기:
    a = 4
    function A() {
        this.a = 3
        this.callA = function() {
            console.log(this.a)
        }
    }
    A() //   undefined, A().callA   。callA    window 
    var a = new A()
    a.callA() // 3,callA new A      
    

    apply/call/bind
    this 가 전달 하 는 첫 번 째 매개 변 수 를 가리 키 는 것 을 잘 알 고 있 을 것 입 니 다. 첫 번 째 매개 변 수 는 null, undefined 또는 전달 되 지 않 으 면 전역 변 수 를 가리 키 는 것 입 니 다.
    a = 3
    function foo() {
        console.log( this.a );
    }
    var obj = {
        a: 2
    };
    foo.call( obj ); // 2
    foo.call( null ); // 3
    foo.call( undefined ); // 3
    foo.call(  ); // 3
    var obj2 = {
        a: 5,
        foo
    }
    obj2.foo.call() // 3,  5!
    //bind        
    function foo(something) {
        console.log( this.a, something );
        return this.a + something;
    }
    var obj =
        a: 2
    };
    var bar = foo.bind( obj );
    var b = bar( 3 ); // 2 3
    console.log( b ); // 5
    

    화살표 함수
    화살표 함수 가 특수 합 니 다. 자신의 this 가 없습니다. 컨 텍스트 (함수 또는 global) 를 폐쇄 적 으로 실행 하 는 this 값 을 사용 합 니 다.
    var x=11;
    var obj={
     x:22,
     say:()=>{
       console.log(this.x); //this  window
     }
    }
    obj.say();// 11
    obj.say.call({x:13}) // 11
    x = 14
    obj.say() // 14
    //    
    var obj2={
     x:22,
     say() {
       console.log(this.x); //this  obj2
     }
    }
    obj2.say();// 22
    obj2.say.call({x:13}) // 13

    이벤트 감청 함수
    바 인 딩 된 dom 요 소 를 가리 키 기
    document.body.addEventListener('click',function(){
        console.log(this)
    }
    )
    //     
    // ...

    HTML HTML 태그 의 속성 에는 JS 가 적 혀 있 을 수 있 습 니 다. 이 경우 this 는 이 HTML 요 소 를 대신 합 니 다.
    document.getElementById("foo").click(); //logs <div id="foo"...

    变量对象

    变量对象是与执行上下文相关的数据作用域,存储了上下文中定义的变量和函数声明。

    变量对象式一个抽象的概念,在不同的上下文中,表示不同的对象

    全局执行上下文的变量对象
    全局执行上下文中,变量对象就是全局对象。
    在顶层js代码中,this指向全局对象,全局变量会作为该对象的属性来被查询。在浏览器中,window就是全局对象。

    var a = 1
    console.log(window.a) // 1
    console.log(this.a) // 1

    함수 실행 컨 텍스트 의 변수 대상
  • 함수 컨 텍스트 에서 변수 대상 VO 는 활동 대상 AO 입 니 다.

  • 초기 화 할 때 arguments 속성 이 있 습 니 다.함수 코드 를 두 단계 로 나 누 어 실행 하 다
    실행 컨 텍스트 에 들 어 갈 때 변수 대상 은 다음 과 같 습 니 다.
  • 형 삼
  • 함수 성명, 기 존 변수 대상 교체
  • 변수 성명, 형 삼 과 함 수 를 교체 하지 않 습 니 다
  • 함수 실행
  • 코드 에 따라 변수 대상 의 값 을 수정 합 니 다.
    예 를 들다
    function test (a,c) {
      console.log(a, b, c, d) // 5 undefined [Function: c] undefined
      var b = 3;
      a = 4
      function c () {
      }
      var d = function () {
      }
      console.log(a, b, c, d) // 4 3 [Function: c] [Function: d]
      var c = 5
      console.log(a, b, c, d) // 4 3 5 [Function: d]
    }
    test(5,6)

    과정 을 분석 해 보도 록 하 겠 습 니 다.
    1. 실행 컨 텍스트 를 만 들 때
    VO = {arguments: {0: 5}, a: 5, b: undefined, c: [Function], / 함수 C 는 인자 c 를 덮어 씁 니 다. 그러나 변수 성명 c 는 함수 c 의 성명 d: undefined, / 함수 표현 식 을 덮어 쓸 수 없습니다. 대응 하 는 문 구 를 실행 하기 전에 undefined}
    코드 를 실행 할 때 마지막 console 를 통 해 함수 성명 이 덮어 쓸 수 있 음 을 알 수 있 습 니 다.
    역할 도 메 인 체인 은 먼저 역할 도 메 인 을 알 아 보 세 요.
    역할 영역
    변수 와 함수 의 접근 가능 범 위 는 변수 와 함수 의 가시 성과 생명주기 를 제어 한다.전역 작용 역 과 국부 작용 역으로 나 뉜 다.
    전역 역할 영역:
    코드 에서 어느 곳 에서 든 접근 할 수 있 는 대상 은 전역 적 인 역할 영역 을 가지 고 있 으 며 다음 과 같은 몇 가지 가 있 습 니 다.
    가장 바깥쪽 에서 정 의 된 변수;
    전역 대상 의 속성
    모든 곳 에서 암시 적 으로 정 의 된 변수 (직접 할당 변수 가 정의 되 지 않 음) 는 모든 곳 에서 암시 적 으로 정 의 된 변 수 는 전체 역할 영역 에서 정 의 됩 니 다. 즉, var 성명 을 통 해 직접 할당 하지 않 는 변 수 를 정의 합 니 다.
    부분 역할 영역:
    JavaScript 의 역할 영역 은 함 수 를 통 해 정 의 됩 니 다. 한 함수 에서 정 의 된 변 수 는 이 함수 내부 에서 만 볼 수 있 습 니 다. 함수 (부분) 역할 영역 이 라 고 합 니 다.
    역할 영역 체인
    역할 도 메 인 체인 은 대상 목록 으로 문맥 코드 에 나타 난 식별 자 를 검색 합 니 다.식별 자 는 변수 이름, 파라미터, 함수 성명 으로 이해 할 수 있다.
    함 수 는 정의 할 때 부모 급 변수 대상 AO / VO 의 집합 을 내부 속성 [scope] 에 저장 합 니 다. 이 집합 을 역할 도 메 인 체인 이 라 고 합 니 다.자유 변 수 는 함수 내부 에 설명 되 지 않 은 변 수 를 말한다.함수 가 자유 변 수 를 방문 해 야 할 때 역할 도 메 인 체인 에 따라 데 이 터 를 찾 습 니 다.하위 대상 은 부모 대상 의 변 수 를 한 단계 한 단계 위로 찾 습 니 다. 부모 대상 의 변 수 는 하위 대상 을 볼 수 있 고 반대로 성립 되 지 않 습 니 다.역할 도 메 인 체인 은 모든 내부 환경 에서 변 수 를 찾 는 체인 시트 입 니 다.
    직접적 으로 말 하면 JS 는 품사 역할 영역 (정적 역할 영역) 을 사 용 했 고 JS 의 함 수 는 그들 이 실 행 된 역할 영역 이 아니 라 정 의 된 역할 영역 에서 실 행 됩 니 다.예 를 들 어 설명 할 수 있다.
    var s = 3
    function a () {
      console.log(s)
    }
    function b () {
      var s = 6
      a()
    }
    b() // 3,  6

    만약 에 js 가 동적 역할 영역 을 사용한다 면 인쇄 된 것 은 3 이 아니 라 6 이 어야 한다. 이 예 는 js 가 정적 역할 영역 이라는 것 을 설명 한다.
    함수 역할 도 메 인 체인 의 의사 코드:
    function foo() {
       function bar() {
           ...
       }
    }
    foo.[[scope]] = [
     globalContext.VO
    ];
    bar.[[scope]] = [
       fooContext.AO,
       globalContext.VO
    ];
    

    함수 가 활성 화 를 실행 할 때 [scope] 속성 을 복사 하여 역할 도 메 인 체인 을 만 든 다음 변수 대상 VO 를 만 든 다음 역할 도 메 인 체인 에 추가 합 니 다.
    executionContextObj: {
        VO:{},
        scopeChain: [VO, [[scope]]]
    }

    폐쇄 하 다
    폐쇄 가 뭐야?
    폐쇄 mdn 의 정의 에 따 르 면
    자유 변 수 는 앞에서 언급 한 바 와 같이 함수 내부 에서 설명 하지 않 는 변 수 를 가리킨다.
    폐쇄 적 형식
    function a() {
        var num = 1
        function b() {
            console.log(num++)
        }
        return b
    }
    var c1 = a()
    c1() // '1'
    c1() // '2'
    var c2 = a()
    c2() // '1'
    c2() // '2'

    폐쇄 적 과정
    엄밀 하 게 쓰 지 는 않 았 습 니 다.이 가능 하 다, ~ 할 수 있다,...
    함수 a 생 성 함수 a 를 실행 하 는 VO 는 변수 num 과 함수 b 정의 함수 b 를 포함 하여 a 의 변수 대상 VO 와 전역 변수 대상 을 [scope] 에서 함수 b 를 되 돌려 주 고 c1 이 c1 을 실행 하 는 역할 도 메 인 체인 에 저장 합 니 다. 이 역할 도 메 인 체인 은 a 의 변수 대상 VO 가 c1 을 만 든 VO 실행 c1 을 저장 합 니 다. 이것 은 방문 변수 num 이 필요 하고 현재 VO 에 존재 하지 않 음 을 발견 합 니 다.따라서 역할 도 메 인 체인 을 통 해 방문 하여 a 의 VO 에 저 장 된 num 을 찾 았 습 니 다. 이 를 조작 합 니 다. num 의 값 은 2 로 설정 되 어 c1 을 다시 실행 하고 두 번 째 작업 을 반복 합 니 다. num 의 값 은 3 가지 문제 로 설정 되 었 습 니 다. 위의 실행 결 과 를 통 해 c2 가 방문 한 num 변수 와 c1 이 방문 한 num 변 수 는 같은 변수 가 아 닙 니 다.우 리 는 코드 를 수정 해서 자신의 추측 을 확인 할 수 있다.
    function a() {
        var x = {y : 4}
        function b() {
            return x
        }
        return b
    }
    var c1 = a()
    var c2 = a()
    c1 === c2()  // false

    따라서 패 킷 이 접근 하 는 변 수 는 부모 함 수 를 실행 할 때마다 다시 만 들 고 서로 독립 된 것 임 을 확인 할 수 있 습 니 다.같은 함수 에서 만 든 자유 변 수 는 서로 다른 패키지 에서 공유 할 수 있 습 니 다.
    function a() {
        var x = 0
        function b() {
            console.log(x++)
        }
        function c() {
            console.log(x++)
        }
        
        return {
            b,
            c
        }
    }
    var r =  a()
    r.b() // 0
    r.c() // 1
    

    역할 영역 체인 과 패 키 지 를 보 는 기 교 를 추가 합 니 다.
    chrome 콘 솔 열기
    console.dir(r.b)
    f b() {
        [[Scopes]]: [
            {x:0}, 
            {type: 'global', name: '', object: Window}
        ]    
    }

    마지막 으로, 우 리 는 상하 문 을 집행 하 는 과정 을 다시 한 번 정리 하여 인상 을 깊 게 한다
    var scope = "global scope";
    function checkscope(a){
        var scope2 = 'local scope';
    }
    checkscope(5);
  • 전역 컨 텍스트 실행 스 택 만 들 기
  • 전역 변수 globalContext. VO 를 만 듭 니 다.
  • checkscope 함수 만 들 기
  • 전역 변수 VO 를 역할 도 메 인 체인 으로 저장 하고 함수 의 내부 속성 [scope]
  • 에 설정 합 니 다.
    checkscope.[[scope]] = [
        globalContext.VO
    ];

    checkscope 함수 생 성 함수 실행 컨 텍스트 를 실행 하고 checkscope 함수 실행 컨 텍스트 를 실행 컨 텍스트 스 택 에 누 릅 니 다.
    ECStack = [
    checkscopeContext,
    globalContext

    ];
    함수 실행 컨 텍스트 생 성 단계
    첫 번 째 단 계 는 [scope] 를 복사 하여 역할 도 메 인 체인 을 만 드 는 것 입 니 다.
    checkscopeContext = {
        Scope: checkscope.[[scope]],
    }

    두 번 째 단 계 는 이벤트 대상 AO 를 만 드 는 것 입 니 다.
    checkscopeContext = {
        AO: {
            arguments: {
                0: 5
                length: 1
            },
            a: 5
            scope2: undefined
        },
        Scope: checkscope.[[scope]],
    }

    세 번 째 단 계 는 활동 대상 AO 를 역할 영역 체인 상단 에 넣 는 것 입 니 다.
    checkscopeContext = {
        AO: {
            arguments: {
                0: 5
                length: 1
            },
            a: 5
            scope2: undefined
        },
        Scope:  [AO, checkscope.[[scope]]],
    }

    네 번 째 단 계 는 this 를 구하 고 상하 문 생 성 단계 가 끝 납 니 다
    여기 this 는 window 와 같 습 니 다.
    함수 실행 단계 에 들 어가 함수 가 실 행 됨 에 따라 AO 의 값 을 수정 합 니 다.
      AO: {
          arguments: {
        0: 5
              length: 1
          },
    a: 5
          scope2: 'local scope'
      },
    

    함수 실행 완료 함수 컨 텍스트 가 컨 텍스트 스 택 에서 팝 업 됩 니 다.
    ECStack = [
        globalContext
    ];

    글 을 비교적 길 게 쓰 고 관련 된 범위 도 비교적 넓 으 니 많은 잘못 이 있 을 수 있 으 니 여러분 들 이 지적 해 주시 기 바 랍 니 다.

    좋은 웹페이지 즐겨찾기