콜백 내에서 올바른 'this'에 액세스하는 방법

javascript callback this


이벤트 핸들러를 등록하는 생성자 함수가 있습니다.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

그러나 콜백 내에서 생성 된 객체 의 data 속성에 액세스 할 수 없습니다 . 것 같습니다 this 생성 된 개체에 있지만 다른 하나를 참조하지 않습니다.

또한 익명 함수 대신 객체 메소드를 사용하려고했습니다.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

그러나 같은 문제가 있습니다.

올바른 개체에 어떻게 액세스 할 수 있습니까?




Answer 1 Felix Kling


this 에 대해 알아야 할 것

this (일명 "컨텍스트")은 각 함수 내부의 특수 키워드이며 그 값 은 함수가 어떻게 / 언제 / 어디서 정의 되었는지가 아니라 함수가 어떻게 호출 되었는지에 달려 있습니다. 다른 변수와 같은 어휘 범위의 영향을받지 않습니다 (화살표 기능 제외, 아래 참조). 여기 몇 가지 예가 있어요.

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

더에 대한 내용 this , 상기보고가 MDN 문서를 .


this 올바르게 참조하는 방법

사용하지 마십시오 this

당신은 실제로 this 에 특히 접근하고 싶지 않지만 그것이 참조하는 객체 입니다. 그렇기 때문에 쉬운 해결책은 단순히 해당 객체를 참조하는 새 변수를 만드는 것입니다. 변수는 이름을 가질 수 있지만, 일반적인 사람들은 selfthat .

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

때문에 self 정상적인 변수, 그것은 어휘 범위 규칙을 따르는 콜백 내부에 액세스 할 수 있습니다. 또한 콜백 자체 this 값에 액세스 할 수 있다는 이점도 있습니다.

this 콜백을 명시 적으로 설정 -1 부

당신의 가치를 통제가없는 것처럼 보일 수 this 값이 자동으로 설정되어 있기 때문에이 있지만 실제로는 그렇지 않습니다.

모든 기능을 가지고있어서 .bind [문서] 와 새로운 함수 반환 this 값으로 결합한다. 이 함수는 호출 한 것과 정확히 같은 행동이 .bind 것만에를 this 당신에 의해 설립되었다. 아니 어떻게 문제 또는 함수가 호출 될 때, this 항상 전달 된 값을 참조합니다.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

이 경우 콜백의 thisMyConstructorthis 값에 바인딩합니다 .

참고 : jQuery에 대한 컨텍스트를 바인딩 할 때는 jQuery.proxy [docs]를 대신 사용하십시오. 이를 수행하는 이유는 이벤트 콜백을 바인딩 해제 할 때 함수에 대한 참조를 저장할 필요가 없기 때문입니다. jQuery는 내부적으로 처리합니다.

ECMAScript 6 : 화살표 기능 사용

ECMAScript 6에는 화살표 함수가 도입 되어 람다 함수로 생각할 수 있습니다. 그들은 this 바인딩을 가지고 있지 않습니다 . 대신 this 일반 변수와 마찬가지로 범위 내에서 조회됩니다. 즉, .bind 를 호출 할 필요가 없습니다 . 이것이 유일한 특수한 행동은 아닙니다. 자세한 내용은 MDN 설명서를 참조하십시오.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

설정 this 콜백의 - 2 부

콜백을 수락하는 일부 함수 / 메소드는 콜백 this 참조해야하는 값도 허용합니다 . 이것은 기본적으로 직접 바인딩하는 것과 동일하지만 함수 / 메소드가 대신합니다. Array#map [docs] 는 그러한 방법입니다. 서명은 다음과 같습니다.

array.map(callback[, thisArg])

첫 번째 인수는 콜백이고 두 번째 인수는 this 참조해야하는 값 입니다. 다음은 좋은 예입니다.

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

참고 : 되는지 여부를 당신이 값 전달할 수 있습니다 this 일반적으로 그 기능 / 방법의 설명서에 언급되어있다. 예를 들어, jQuery의 $.ajax 메소드 [docs]context 라는 옵션을 설명합니다 .

이 객체는 모든 Ajax 관련 콜백의 컨텍스트가됩니다.


일반적인 문제 : 콜백 / 이벤트 핸들러로 객체 메소드 사용

이 문제의 또 다른 일반적인 표현은 객체 메소드가 콜백 / 이벤트 핸들러로 사용될 때입니다. 함수는 JavaScript에서 일류 시민이며 "메소드"라는 용어는 객체 속성 값인 함수에 대한 구어체 용어 일뿐입니다. 그러나이 함수에는 "포함"개체에 대한 특정 링크가 없습니다.

다음 예제를 고려하십시오.

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

함수 this.method 는 클릭 이벤트 핸들러로 할당되지만 있으면된다 document.body 클릭하면, 값이 될 기록 undefined 이벤트 핸들러에 있기 때문에, this 받는 의미 document.body 아니라 인스턴스 Foo .
처음에 이미 언급했듯이, this 참조하는 것은 함수가 어떻게 정의 되는지가 아니라 함수가 어떻게 호출 되는지에 달려 있습니다.
코드가 다음과 같으면 함수에 객체에 대한 암시 적 참조가없는 것이 더 분명 할 수 있습니다.

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

해결책 은 위에서 언급 한 것과 동일합니다. 사용 가능한 경우 .bind 를 사용 하여이를 특정 값에 명시 적으로 바인딩 this

document.body.onclick = this.method.bind(this);

또는 익명 함수를 콜백 / 이벤트 핸들러로 사용하여 객체의 "메서드"로 함수를 명시 적으로 호출하고 객체 ( this )를 다른 변수에 할당합니다 .

var self = this;
document.body.onclick = function() {
    self.method();
};

또는 화살표 기능을 사용하십시오.

document.body.onclick = () => this.method();



Answer 2 Mohan Dere


자식 컨텍스트 내에서 부모 컨텍스트에 액세스하는 몇 가지 방법이 있습니다.

  1. bind() 함수를 사용할 수 있습니다 .
  2. 컨텍스트 / this에 대한 참조를 다른 변수 안에 저장하십시오 (아래 예 참조).
  3. ES6 화살표 기능을 사용하십시오 .
  4. 코드 / 함수 디자인 / 아키텍처 변경-이를 위해서는 자바 스크립트의 디자인 패턴 에 대한 명령이 있어야합니다 .

1. bind() 함수를 사용하십시오

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

underscore.js 를 사용중인 경우 -http : //underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2 컨텍스트 / this에 대한 참조를 다른 변수에 저장하십시오.

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3 화살표 기능

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}



Answer 3 Guffa


메소드 호출의 모든 "마법"구문에 있습니다.

object.property();

객체에서 속성을 가져 와서 한 번에 호출하면 객체가 메서드의 컨텍스트가됩니다. 동일한 방법을 별도의 단계로 호출하면 컨텍스트는 전역 범위 (창)가됩니다.

var f = object.property;
f();

메소드의 참조를 얻으면 더 이상 객체에 연결되지 않으며 단지 일반 함수에 대한 참조 일뿐입니다. 콜백으로 사용할 참조를 얻을 때도 마찬가지입니다.

this.saveNextLevelData(this.setAll);

여기서 컨텍스트를 함수에 바인딩 할 수 있습니다.

this.saveNextLevelData(this.setAll.bind(this));

jQuery를 사용하는 경우 모든 브라우저에서 bind 가 지원되지 않으므로 $.proxy 메소드를 대신 사용해야 합니다.

this.saveNextLevelData($.proxy(this.setAll, this));



Answer 4 RobG


"문맥"의 문제

"컨텍스트"라는 용어는 때때로 이것에 의해 참조되는 객체를 지칭하기 위해 사용된다 . 의미 적으로 또는 기술적으로 ECMAScript의 this 와 맞지 않기 때문에 부적절한 사용입니다 .

"컨텍스트" 는 의미를 추가하는 것을 둘러싼 상황 또는 추가 의미를 부여하는 일부 선행 및 후속 정보를 의미합니다. 용어 "콘텍스트"를 참조로 사용되는 ECMAScript를 실행 컨텍스트 모든 파라미터 범위 인, 및 일부의 실행 코드의 범위 내.

이는 ECMA-262 섹션 10.4.2에 나와 있습니다 .

ThisBinding을 호출 실행 컨텍스트의 ThisBinding과 동일한 값으로 설정하십시오.

이것은 이것이 실행 컨텍스트의 일부 임을 분명히 나타냅니다 .

실행 컨텍스트는 실행중인 코드에 의미를 추가하는 주변 정보를 제공합니다. thisBinding 보다 훨씬 더 많은 정보를 포함합니다 .

의 값 그래서 "컨텍스트"아니다, 그것은 실행 컨텍스트의 한 부분입니다. 본질적으로 모든 객체에 대한 호출과 엄격 모드에서 모든 값으로 설정할 수있는 로컬 변수입니다.




Answer 5 Ashish


"this"키워드에 대해 알아야합니다.

내 관점에 따라 세 가지 방법으로 "this"를 구현할 수 있습니다 (Self / Arrow 함수 / Bind Method)

함수의이 키워드는 JavaScript에서 다른 언어와 약간 다르게 작동합니다.

또한 엄격 모드와 엄격하지 않은 모드 사이에는 약간의 차이가 있습니다.

대부분의 경우이 값은 함수 호출 방법에 따라 결정됩니다.

실행 중에 할당하여 설정할 수 없으며 함수가 호출 될 때마다 다를 수 있습니다.

ES5는 bind () 메소드를 도입하여 호출 방법에 관계없이 함수의 값을 설정합니다.

그리고 ES2015는 자체적으로이 바인딩을 제공하지 않는 화살표 함수를 도입했습니다 (이것은 묶는 어휘 문맥의이 값을 유지합니다).

방법 1 : 자체-컨텍스트가 변경되는 경우에도 자체를 사용하여 원본에 대한 참조를 유지합니다. 이벤트 처리기 (특히 클로저)에서 자주 사용되는 기술입니다.

참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

Method2 : 화살표 함수-화살표 함수 표현식은 정규 함수 표현식에 대한 구문 상 컴팩트 한 대안입니다.

this, arguments, super 또는 new.target 키워드에 대한 바인딩이없는 경우에도 마찬가지입니다.

화살표 함수 표현식은 메서드로 적합하지 않으며 생성자로 사용할 수 없습니다.

참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

Method3 : Bind- bind () 메소드는 새로운 함수를 생성합니다.

호출되면이 키워드가 제공된 값으로 설정되어 있으며

새로운 함수가 호출 될 때 제공된 일련의 인수를 제공합니다.

Reference:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);