JavaScript의 this 지향 및 바인딩 상세 정보

주의: 본고는 기초편에 속하니 정신을 차리십시오.만약 네가 이해하지 못하거나 아직 완전하지 않다면, 본문을 통해 복습할 수 있다.
this가 가리키는 유형
자바스크립트를 처음 배울 때,this는 항상 사람을 가장 현혹시킨다. 자바스크립트에서this의 지향을 어떻게 확정해야 하는지 살펴본다.
this는 함수가 호출될 때 확정되며, 그 지향은 함수가 호출되는 곳에 달려 있으며, 설명된 곳에 달려 있지 않습니다. (화살표 함수를 제외하고)함수가 호출될 때 실행 상하문을 만듭니다. 함수가 어디서 호출되는지 (호출 창고), 함수의 호출 방식, 전송된 매개 변수 등 정보를 포함합니다.this는 이 기록의 속성입니다. 함수가 실행되는 과정에서 사용됩니다.
this는 함수의 지향점에 다음과 같은 몇 가지 장면이 있습니다.
  • 구조 함수로 new에서 호출됩니다
  • 대상의 방법으로 사용한다
  • 함수로 직접 호출합니다
  • 콜,apply,bind에 호출됩니다
  • 화살표 함수의this
  • 다음은 이 장면들 중this의 지향점을 각각 토론해 봅시다.
    1.new 바인딩
    함수가 구조 함수로 new 호출을 사용할 때,this는 새로 만든 구조 함수의 실례를 연결합니다.
    
    function Foo() {
     console.log(this)
    }
    
    var bar = new Foo() //  : Foo  ,this   bar
    실제로 new를 사용하여 구조 함수를 호출할 때 다음 동작을 순서대로 실행합니다.
  • 새 대상을 만듭니다
  • 구조 함수의prototype이 새 대상의 ___에 값을 부여합니다.proto__
  • 새로운 대상을 현재this에 부여합니다
  • 구조 함수를 실행합니다
  • 함수가 다른 대상을 되돌려 주지 않으면, new 표현식의 함수 호출은 자동으로 이 새로운 대상을 되돌려줍니다. 대상이 아닌 것을 되돌려주면 무시됩니다.
  • 2. 현식 귀속
    콜,apply,bind를 통해 함수 귀속된this를 수정하여 우리가 지정한 대상이 될 수 있습니다.이 방법의 첫 번째 매개 변수를 통해 우리는this를 현저하게 연결할 수 있다.
    
    function foo(name, price) {
     this.name = name
     this.price = price
    }
    
    function Food(category, name, price) {
     foo.call(this, name, price) // call  
     // foo.apply(this, [name, price])  // apply  
     this.category = category
    }
    
    new Food(' ', ' ', '5 ')
    
    //  : {name: " ", price: "5 ", category: " "}
    call과 apply의 차이는call 방법은 매개 변수 목록을 받아들이고, apply 방법은 매개 변수 그룹을 받아들인다는 것이다.
    
    func.call(thisArg, arg1, arg2, ...)    // call  
    func.apply(thisArg, [arg1, arg2, ...])   // apply  
    bind 방법은this를 주어진 값으로 설정하고 새로운 함수를 되돌려주며, 새로운 함수를 호출할 때, 주어진 매개 변수 목록을 원 함수의 매개 변수 서열의 앞부분으로 하는 것이다.
    
    func.bind(thisArg[, arg1[, arg2[, ...]]])  // bind  
    예:
    
    var food = {
     name: ' ',
     price: '5 ',
     getPrice: function (place) {
      console.log(place + this.price)
     },
    }
    
    food.getPrice('KFC ') //  : "KFC 5 "
    
    var getPrice1 = food.getPrice.bind({ name: ' ', price: '7 ' }, '  ')
    getPrice1() //  : "  7 "
    bind의 원리에 관해서 우리는 apply 방법을 사용하여 스스로 bind를 실현할 수 있다.
    
    // ES5  
    Function.prototype.bind =
     Function.prototype.bind ||
     function () {
      var self = this
      var rest1 = Array.prototype.slice.call(arguments)
      var context = rest1.shift()
      return function () {
       var rest2 = Array.prototype.slice.call(arguments)
       return self.apply(context, rest1.concat(rest2))
      }
     }
    
    // ES6  
    Function.prototype.bind =
     Function.prototype.bind ||
     function (...rest1) {
      const self = this
      const context = rest1.shift()
      return function (...rest2) {
       return self.apply(context, [...rest1, ...rest2])
      }
     }
    ES6 방식은 일부 ES6의 지식, 예를 들어rest 매개 변수, 수조 해체를 사용했다.
    주의:null이나undefined를this의 귀속 대상으로call,apply,bind에 전송하면 이 값은 호출할 때 무시됩니다. 실제 적용되는 것은 기본 귀속 규칙입니다.
    
    var a = 'hello'
    
    function foo() {
     console.log(this.a)
    }
    
    foo.call(null) //  : "hello"
    3. 암시적 귀속
    함수가 어떤 상하문 대상에서 호출되는지, 만약 그렇다면this가 귀속된 것은 그 상하문 대상이다.
    
    var a = 'hello'
    
    var obj = {
     a: 'world',
     foo: function () {
      console.log(this.a)
     },
    }
    
    obj.foo() //  : "world"
    위 코드에서foo방법은 대상의 속성으로 호출된 것입니다. 그러면 이때foo방법이 실행될 때,this는obj대상을 가리킵니다.즉, 이때this는 이 방법을 호출하는 대상을 가리키고 여러 개의 대상을 끼워 넣으면 마지막으로 이 방법을 호출하는 대상을 가리킨다.
    
    var a = 'hello'
    
    var obj = {
     a: 'world',
     b: {
      a: 'China',
      foo: function () {
       console.log(this.a)
      },
     },
    }
    
    obj.b.foo() //  : "China"
    마지막 대상은obj의 b입니다. 그러면 이때foo방법이 실행될 때 그 중this가 가리키는 것은 b대상입니다.
    4. 기본 바인딩
    함수가 독립적으로 호출되고 어떠한 수식도 없는 함수 인용을 직접 사용하여 호출하는 것도 상기 몇 가지 귀속 경로 이외의 방식이다.비엄격한 모드에서this는 전역 대상(브라우저 아래는winodw,node 환경은global), 엄격한 모드에서this는undefined로 귀속됩니다(엄격한 모드에서this가 전역 대상을 가리키는 것을 허용하지 않기 때문).
    
    var a = 'hello'
    
    function foo() {
     var a = 'world'
     console.log(this.a)
     console.log(this)
    }
    
    foo() //   window.foo()
    
    //  : "hello"
    //  : Window  
    위 코드에서 변수 a는 전역 작용역에 성명되어 전역 대상 윈도우의 동명 속성이 됩니다.함수foo가 실행될 때,this는 전역 대상을 가리키기 때문에 출력된 a는 전역 대상의 속성입니다.
    참고:
    
    var a = 'hello'
    
    var obj = {
     a: 'world',
     foo: function () {
      console.log(this.a)
     },
    }
    
    var bar = obj.foo
    
    bar() //  : "hello"
    이때 bar 함수, 즉obj의foo방법은 왜 전역 대상을 가리키는가. bar 방법은 이때 함수로 독립적으로 호출되기 때문에 이 장면은 기본 귀속에 속하고 은식 귀속이 아니다.이러한 상황은 메서드를 콜백 함수로 사용하는 장면과 유사합니다.
    
    var a = 'hello'
    
    var obj = {
     a: 'world',
     foo: function () {
      console.log(this.a)
     },
    }
    
    function func(fn) {
     fn()
    }
    
    func(obj.foo) //  : "hello"
    매개 변수 전달도 사실상 은밀한 값이다. 단지 여기obj에 불과하다.foo 방법은 은식부치에 의해 함수func의 형삼 fn에 부여되었고 이전의 상황은 자신이 부여한 것으로 두 가지 상황은 실제로 유사하다.이런 장면에서 우리가 비교적 많이 만나는 것은 set Timeout과 set Interval이다. 만약에 리셋 함수가 화살표 함수가 아니라면this가 가리키는 것은 전역 대상이다.
    사실 우리는 기본 귀속을 은식 귀속의 특수한 상황으로 여길 수 있다. 예를 들어 위의bar (), 우리는 윈도우를 사용하는 것으로 여길 수 있다.bar () 방식으로 호출되었습니다. 이때 bar의this는 은식으로 연결된 상황에 따라 윈도우를 가리킵니다.
    this 귀속 우선 순위
    this는 여러 개의 사용 장면이 존재한다. 그러면 여러 장면이 동시에 나타날 때this는 도대체 어떻게 가리켜야 하는가.여기에 우선순위의 개념이 존재한다.this는 우선순위에 따라 지향을 확정한다.우선 순위: new 바인딩 > 표시 바인딩 > 스텔스 바인딩 > 기본 바인딩
    그래서this의 판단 순서:
  • new 귀속: 함수가 new에서 호출됩니까?만약 그렇다면this는 새로 만든 대상입니다
  • 현식 귀속: 함수는bind,call,apply를 통해 호출됩니까?만약 그렇다면,this는 지정된 대상입니다
  • 은식 귀속: 함수가 어떤 상하문 대상에서 호출됩니까?만약 그렇다면,this가 귀속된 것은 그 상하문 대상이다
  • 모두 그렇지 않으면 기본 귀속을 사용합니다.엄격한 모드에서 undefined에 귀속합니다. 그렇지 않으면 전역 대상에 귀속됩니다.
  • 화살표 함수의this
    화살표 함수는 선언된 곳에 따라this를 결정합니다. 이것은 ES6의 지식점입니다.
    화살표 함수의this 귀속은call,apply,bind를 통해 수정될 수 없으며, 화살표 함수에 구조 함수constructor가 없기 때문에 new 호출을 사용할 수 없습니다. 즉, 구조 함수로 사용할 수 없습니다. 그렇지 않으면 오류가 발생합니다.
    
    var a = 'hello'
    
    var obj = {
     a: 'world',
     foo: () => {
      console.log(this.a)
     },
    }
    
    obj.foo() //  : "hello"
    ECMAScript 표준에서 화살표 함수에 대한 설명을 볼 수 있습니다.
    원문:
    An Arrow Function does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.
    번역:
    화살표 함수는arguments, 슈퍼,this 또는 new가 아닙니다.target은 로컬 귀속을 정의합니다.화살표 함수에서arguments, 슈퍼,this 또는 new.target의 모든 인용은 현재 있는 어법 작용 영역의 귀속으로 해석됩니다.일반적으로 이것은 화살표 함수가 있는 함수 작용역입니다.
    ―ECMAScript Language Specification - Arrow Function | ECMA 표준 - 화살표 함수
    this의 작은 연습
    작은 연습으로 실전을 해보세요.
    
    var a = 20
    
    var obj = {
     a: 40,
     foo: () => {
      console.log(this.a)
    
      function func() {
       this.a = 60
       console.log(this.a)
      }
    
      func.prototype.a = 50
      return func
     },
    }
    
    var bar = obj.foo() //  : 20
    bar() //  : 60
    new bar() //  : 60
    조금만 설명해 주세요.
    1) var a = 20 이 문장은 전역 변수 윈도우에 속성 a를 만들고 값을 20으로 부여합니다.
    2) 우선 obj를 실행합니다.foo(), 이것은 화살표 함수입니다. 화살표 함수는 새로운 함수 작용역을 만들지 않고 문장 외부의 작용역을 그대로 사용합니다. 따라서obj.foo()가 실행될 때 화살표 함수 중this는 전역 윈도우입니다. 먼저 윈도우의 속성 a의 값 20을 출력하고 화살표 함수는 원형에 50의 속성 a의 함수 대상인 func를 bar에 되돌려줍니다.
    3) 계속 실행하는 것은 bar (), 여기 실행하는 것은 방금 화살표 함수가 되돌아온 패키지 func입니다. 그 내부의this는 윈도우를 가리키기 때문에this.a 윈도우를 수정했습니다.a의 값은 60이고 출력합니다.
    4) 그리고 실행하는 것은 newbar()입니다. 이전의 설명에 의하면 new 조작부호는func 함수에서func 원형을 계승한 실례 대상을 만들고this로 가리키며this.a = 60은 실례 대상에 속성 a를 만들었고 이후 인쇄에서 실례에서 속성 a를 찾았기 때문에 대상의 원형을 계속 찾지 않기 때문에 세 번째 60을 출력합니다.
    만약 상기 예의 화살표 함수를 일반 함수로 바꾸면 결과는 어떻게 될까요?
    
    var a = 20
    
    var obj = {
     a: 40,
     foo: function () {
      console.log(this.a)
    
      function func() {
       this.a = 60
       console.log(this.a)
      }
    
      func.prototype.a = 50
      return func
     },
    }
    
    var bar = obj.foo() //  : 40
    bar() //  : 60
    new bar() //  : 60
    이 예는 상세하게 설명하지 않는다.
    만약 위의 두 가지 예를 원리를 이해한다면 기본적으로this의 지향은 파악할 수 있는 차이가 많지 않을 것이다~
    이상은 자바스크립트의this지향과 귀속에 대한 상세한 내용입니다. 자바스크립트의this지향과 귀속에 관한 더 많은 자료는 저희 다른 관련 글을 주목해 주십시오!

    좋은 웹페이지 즐겨찾기