중첩 된 함수 내의 자바 스크립트 "this"포인터


94

중첩 된 함수 시나리오에서 "this"포인터가 어떻게 처리되는지에 대한 질문이 있습니다.

다음 샘플 코드를 웹 페이지에 삽입한다고 가정 해 보겠습니다. 중첩 함수 "doSomeEffects ()"를 호출 할 때 오류가 발생합니다. Firebug에서 확인한 결과 중첩 된 함수에있을 때 "this"포인터가 실제로 전역 "window"개체를 가리키고 있음을 나타냅니다. 객체의 함수 내에서 중첩 된 함수를 선언했기 때문에 뭔가를 올바르게 이해하고 있지 않아야합니다. 함수와 관련하여 "로컬"범위를 가져야합니다 (즉, "this"포인터는 다음과 같이 객체 자체를 참조 할 것입니다). 내 첫 "if"문에서 어떻게되는지).

모든 포인터 (말장난 의도 없음)를 주시면 감사하겠습니다.

var std_obj = {
  options : { rows: 0, cols: 0 },
  activeEffect : "none",
  displayMe : function() {

    // the 'this' pointer is referring to the std_obj
    if (this.activeEffect=="fade") { }

    var doSomeEffects = function() {

      // the 'this' pointer is referring to the window obj, why?
      if (this.activeEffect=="fade") { }

    }

    doSomeEffects();   
  }
};

std_obj.displayMe();

당신의 질문은 정확히 무엇입니까?
Sarfraz

2
함수 내에서 사용될 때 this함수가 호출되는 객체를 나타냅니다.
approxiblue

8
외부 스코프에서 할 수있는 것은 클로저를 통해 내부 함수에서 var self = this;참조 할 수 self있습니다.
Kai

1
doSomeEffects특히 obj와 관련이 없으므로 this모든 요소의 어머니 인 창이라고 가정합니다.
approxiblue

3
@JoJoeDad 외교적으로 이것을 어떻게 말합니까? 그러나 아래 chuckj가 제공하는 대답은 귀하의 질문에 대한 대답입니다. 진행 상황을 진정으로 이해하려면 실행 컨텍스트 , 범위 체인이 키워드를 읽어야 합니다 . 그리고 여기에있는 일부 답변의 모습에서 다른 사람들도 읽어야합니다. 좋은 자바 스크립트를 전파하려고합니다. 이것이 내가 이러한 링크를 제공하는 데 시간을 할애하는 이유입니다.
onefootswill 2013

답변:


120

JavaScript에서 this객체는 실제로 함수 호출 방법을 기반으로합니다.

일반적으로 this개체 를 설정하는 세 가지 방법이 있습니다 .

  1. someThing.someFunction(arg1, arg2, argN)
  2. someFunction.call(someThing, arg1, arg2, argN)
  3. someFunction.apply(someThing, [arg1, arg2, argN])

위의 모든 예에서 this객체는 someThing. 선행 부모 개체없이 함수를 호출하면 일반적으로 대부분의 브라우저에서 개체를 의미하는 전역 개체를 얻을 수 있습니다 window.


this.doSomeEffects();귀하의 답변에 따라 코드를 변경 했지만 여전히 작동하지 않습니다. 왜?
Arashsoft

1
@Arashsoft thisthis.doSomeEffects()포인트 std_obj. 위의 답변에서 설명한 것처럼 함수에 개체 참조가 없으면 this창 개체가 필요합니다.
Shivam

38

이 질문이 가장 많이 찬성 된 질문 중 하나 인 것처럼 보이므로 몇 년이 지난 후에도 화살표 기능을 사용하는 ES6 솔루션을 추가하겠습니다.

var std_obj = {
  ...
  displayMe() {
    ...
    var doSomeEffects = () => {
                        ^^^^^^^    ARROW FUNCTION    
      // In an arrow function, the 'this' pointer is interpreted lexically,
      // so it will refer to the object as desired.
      if (this.activeEffect=="fade") { }
    };
    ...    
  }
};

5
지금 의 그 진행!
여호수아 핀터

훌륭하고 간단하며 솔루션입니다.
Joshua Schlichting

32

this클로저 범위의 일부가 아니므로 호출 사이트에 바인딩 된 함수에 대한 추가 매개 변수로 생각할 수 있습니다. 메서드가 메서드로 호출되지 않으면 전역 개체가 this. 브라우저에서 전역 개체는 window. 예를 들어, 다음 기능을 고려하십시오.

function someFunction() {
}

다음 객체,

var obj = { someFunction: someFunction };

다음과 같은 메서드 구문을 사용하여 함수를 호출하면

obj.someFunciton();

그런 다음 this에 바인딩됩니다 obj.

다음과 같이 someFunction ()을 직접 호출하면

someFunction();

그런 다음 this전역 개체, 즉 window.

가장 일반적인 해결 방법은 다음과 같은 클로저에이를 캡처하는 것입니다.

displayMe : function() {      

    // the 'this' pointer is referring to the std_obj      
    if (this.activeEffect=="fade") { }      
    var that = this;  
    var doSomeEffects = function() {      

      // the 'this' pointer is referring to global
      // that, however, refers to the outscope this
      if (that.activeEffect=="fade") { }      
    }      

    doSomeEffects();         
 }      

that = this is perfect
Nather Webber

10

엔클로저 변수와 "this"에는 차이가 있습니다. "this"는 실제로 함수 호출자에 의해 정의되는 반면 명시 적 변수는 인클로저로 알려진 함수 선언 블록 내부에 그대로 남아 있습니다. 아래 예를 참조하십시오.

function myFirstObject(){
    var _this = this;
    this.name = "myFirstObject";
    this.getName = function(){
       console.log("_this.name = " + _this.name + " this.name = " + this.name);  
    }
}

function mySecondObject(){
    var _this = this;
    this.name = "mySecondObject";
    var firstObject = new myFirstObject();
    this.getName = firstObject.getName
}

var secondObject = new mySecondObject();
secondObject.getName();

여기에서 시도해 볼 수 있습니다 : http://jsfiddle.net/kSTBy/

함수에서 일어나는 일은 "doSomeEffects ()"이며, 명시 적으로 호출됩니다. 이것은 컨텍스트를 의미하거나 함수의 "this"가 창이라는 것을 의미합니다. 만약 "doSomeEffects"가 "myObject"라고 말하는 this.doSomeEffects와 같은 프로토 타입 메소드라면, myObject.doSomeEffects ()는 "this"가 "myObject"가되게합니다.


4
이 데모 로그, 게으른과 참을성을위한 :_this.name = myFirstObject this.name = mySecondObject
ptim

9

이 질문을 이해하려면 다음 스 니펫에 대한 출력을 얻으십시오.

var myObject = {
    foo: "bar",
    func: function() {
        var self = this;
        console.log("outer func:  this.foo = " + this.foo);
        console.log("outer func:  self.foo = " + self.foo);
        (function() {
            console.log("inner func:  this.foo = " + this.foo);
            console.log("inner func:  self.foo = " + self.foo);
        }());
    }
};
myObject.func();

위의 코드는 콘솔에 다음을 출력합니다.

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

외부 함수에서 this와 self는 모두 myObject를 참조하므로 둘 다 foo를 올바르게 참조하고 액세스 할 수 있습니다.

그러나 내부 함수에서는 더 이상 myObject를 참조하지 않습니다. 결과적으로 this.foo는 내부 함수에서 정의되지 않은 반면 지역 변수 self에 대한 참조는 범위에 남아 있으며 액세스 할 수 있습니다. (ECMA 5 이전에는 내부 함수에서 전역 창 개체를 참조하는 반면 ECMA 5에서는 내부 함수에서 정의되지 않았습니다.)


1
내부 함수 this에서 창 개체 (브라우저 환경에서) 또는 GLOBAL 개체 (node.js 환경에서)를 참조합니다
raneshu

2
왜 그럴까요?
setu

@raneshu "엄격한 사용하지"하고 this더 이상 창을 말한다
rofrol

3

Kyle이 설명했듯이 함수 내에서 call또는 apply을 사용 하여 지정할 수 있습니다 this.

코드에 적용된 개념은 다음과 같습니다.

var std_obj = {
    options: {
        rows: 0,
        cols: 0
    },
    activeEffect: "none",
    displayMe: function() {

        // the 'this' pointer is referring to the std_obj
        if (this.activeEffect == "fade") {}

        var doSomeEffects = function() {
            // the 'this' pointer is referring to the window obj, why?
            if (this.activeEffect == "fade") {}
        }

        doSomeEffects.apply(this,[]);
    }
};

std_obj.displayMe();

JsFiddle


0

또한 "경고있어 이를 통해 클래스 필드에 잠재적으로 잘못된 참조 액세스 "

class MyListItem {
    constructor(labelPrm) {
        this._flagActive = false;
        this._myLabel = labelPrm;
        labelPrm.addEventListener('click', ()=>{ this.onDropdownListsElementClick();}, false);
    }

    get myLabel() {
        return this._myLabel
    }
    get flagActive(){
        return this._flagActive;
    }

    onDropdownListsElementClick(){console.log("Now'this'refers to the MyListItem itself")}}//end of the class

0

언급되지 않았기 때문에 사용 .bind()이 해결책 이라고 언급하겠습니다.


        doSomeEffects=doSomeEffect.bind(this);
        doSomeEffects();   
      }
    };

    std_obj.displayMe();

다음은 더 간단한 예입니다.

bad = { 
  name:'NAME', 
  z : function() { 
    function x() { console.log(this.name); }; 
    x() 
  } 
};
bad.z() // prints 'undefined'

good = { 
  name:'NAME', 
  z : function() { 
    function x() { console.log(this.name); }; 
    x=x.bind(this);
    x();
  } 
};
good.z() // prints 'NAME'

화살표 기능을 사용하는 =>것이 더 매끄럽고 프로그래머에게 쉬운 것은 사실입니다 . 그러나 어휘 범위는 단순히 this를 통해 함수를 포인터와 연결하는 것과 비교하여 어휘 범위를 설정하고 유지하기 위해 처리 및 메모리 측면에서 더 많은 작업이 필요할 수 있다는 점을 염두에 두어야합니다 .bind().

JS에서 클래스를 개발할 때의 이점 중 일부는 this보다 안정적으로 존재하고 사용 가능하게 만들고 함수형 프로그래밍 및 어휘 범위에서 벗어나 오버 헤드를 줄이는 방법을 제공하는 것 입니다.

MDN에서

성능 고려 사항 특정 작업에 대해 클로저가 필요하지 않은 경우 다른 함수 내에서 불필요하게 함수를 만드는 것은 현명하지 않습니다. 처리 속도와 메모리 소비 측면에서 스크립트 성능에 부정적인 영향을 미치기 때문입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.