4

중첩 된 개체 리터럴에서 화살표 키를 사용하면 'this'키워드가 항상 global을 가리키는 것으로 나타났습니다.중첩 된 객체 리터럴 내에서 화살표 함수의 'this'가 변경되지 않는 이유는 무엇입니까?

다른 질문에 따르면, 다음 스 니펫은 화살표 함수의 'this'가 어휘 적 맥락에서 정의 된 것으로 설명 할 수 있습니다.

var c = 100; 

var a = { 
    c: 5, 
    b: { 
     c: 10, 
     fn:()=> {return this.c;} 
    } 
} 

console.log(a.b.fn());// still 100, why not 5? 

나는, 어휘 문맥 측면에서 고려한다면,해야하지 '이'의미 abfn 포인트 :

var c = 100; 
var a = {c:5 , fn:() => {return this.c;} }; 
console.log(a.c); //100 

그러나, 나는 다음과 같은 코드 (문자 중첩 된 객체)를 이해할 수 없다 ~에?

왜 개체가 몇 개 중첩되어 있어도 'this'인스턴스가 모두 창 또는 전역을 가리 킵니까?

+2

현재 범위를 가리 킵니다. 객체는 범위를 변경하지 않고 범위 만 변경합니다. 따라서 화살표 함수 내부의 'this'는 내부에있는 가장 가까운 함수를 나타냅니다. 귀하의 경우, 그것은 단지 최상위 수준입니다. – mash

+1

@mash :'this'와 범위는 크게 관련이 없으며 'this'는 드물게 ... [a] 함수를 나타냅니다. " 그러나 논평의 요지는 물론 정확합니다. –

+0

레코드 용 : 화살표 기능은 범위와 마찬가지로 기능을 변경합니다. 그들은 단지'this','arguments','super'와'new.target'을 어휘 적으로 묶습니다. –

답변

2

범위를 변경하는 유일한 표현식은 함수이며, ES6에서 블록 (주위에 중괄호가 있음에도 불구하고 객체 리터럴이 블록 이 아니라이 아니라 블록 임)에 유의하십시오. 즉, 함수 안에없는 모든 것이 전역 범위에 있습니다.

전역 범위에서 this은 전역 개체 (브라우저의 경우 window)를 나타냅니다. 범위를 변경하는 유일한 방법은 화살표 기능입니다 (예, 범위를 변경합니다.) -하지만 어휘 적으로 바인딩합니다. 즉, 외부 범위의 this을 사용하므로 전역 개체입니다.

당신이 this 대신 객체 리터럴의 인생을의 a 객체를 참조 사용할 경우 :

var c = 100; 

var a = { 
    c : 5, 
    b : new function() { 
     this.c = 10; 
     this.fn =()=> {return this.c;} 
    }() 
} 

alert(a.b.fn()) // 10; 
또는

, 바인딩 :

var c = 100; 

var a = new function() { 
    this.c = 5; 
    this.b = { 
     c: 10, 
     fn:()=> {return this.c;} 
    } 
}() 

alert(a.b.fn()) // 5; 

또는 bthis에 바인딩하기 this ~ b이면 화살표 기능 대신 일반 기능을 사용할 수도 있습니다.

var c = 100; 

var a = { 
    c: 5, 
    b: { 
     c: 10, 
     fn: function() {return this.c;} 
    } 
} 

alert(a.b.fn()) // 10; 
+0

"* JavaScript에서 범위를 변경하는 유일한 표현식은 함수입니다."- nope. 블록도 마찬가지입니다. – Bergi

+0

@Bergi 나는 당신에게 동의한다. 그래서 나는 중첩 된 객체 리터럴에서 'this'에 대해 혼란스러워했다. –

+0

@ jt-wang :하지만 객체 리터럴은 블록이 아닙니다 :-) – Bergi

3

이것은 객체 이니셜 라이저가있는 this과 같습니다. 따라서 두 예 모두에서 var a = ... 행이있는 곳은 this과 같습니다. this은 지정된 실행 컨텍스트 내에서 절대 변경되지 않으며 개체 이니셜 라이저는 새 실행 컨텍스트를 만들지 않습니다. 기능 만이 eval입니다. 귀하의 예제에서 새로운 실행 컨텍스트가 생성되는 유일한 시간은 fn이고 fn은 화살표 함수이므로 이 작성된 실행 컨텍스트에서 닫힙니다 (이는 글로벌 실행 컨텍스트가됩니다). 귀하의 예).

당신이 당신의 예제 코드에 this.c에 대한 100을 볼 수있는 이유는 전역 범위에서 this가 (느슨한 모드) 전역 객체를 참조하고 글로벌 범위에서 var 변수는 전역 객체의 속성이 될, 그래서 this.c는 점이다 c 전역 변수.

이 같은 범위 지정 기능에 그 모든 코드를 넣을 경우 :

는 는
(function() { // Or `(() => {`, doesn't matter in this case 
    var c = 100; 

    var a = { 
     c: 5, 
     b: { 
      c: 10, 
      fn:()=> {return this.c;} 
     } 
    } 
    console.log(a.b.fn());// still 100, why not 5? 
})();  

... this 여전히 전역 객체를 참조 것이지만 때문에 this.c는, undefined 것, c는 더 이상 없을 것 전역 변수 (따라서 전역 개체의 속성). 당신이 thisfn 내부는 식 a.b.fn()b 참조 할 경우

, 당신은 당신이 정상적인 기능을 원하는,이 화살표의 기능을 원하지 않는; 5 (a.c 값)이 아닌 (a.b.c 값)을 얻게됩니다. 물론

, 이것은 일회성 개체이며 fna 이상 닫로, 당신은 또한 단지 fn의 몸 return a.c; 또는 return a.b.c; 원하는 c에 따라 만들 수 있습니다.

+0

두 번째 코드 스 니펫은 어떻게됩니까? 'b'는'a'에서 시작되지만 왜'a.b.c'는'a.c'가 아닌 global의 c를 가리 킵니까? –

+1

@ jt-wang : 두 번째 발췌 문장에 대해 이야기하고있었습니다. :-)'this.c'는 첫 번째와 같은 이유로이 예제에서'c' 글로벌을 가리 킵니다 :'this'는 여전히'var a' 라인과 동일합니다. 'this'는 실행 컨텍스트 내에서 변경되지 않으며, 객체 초기화 프로그램은 새로운 실행 컨텍스트 (함수와'eval' do 만)를 생성하지 않습니다. –

1

이것에 대해 생각해 볼 수있는 또 다른 방법은 리터럴 안에 새로운 "this"범위의 개념이 없다는 것입니다.

함수는 새로운 범위를 도입합니다.