programing tip

자바 스크립트 콜백 범위

itbloger 2020. 12. 12. 10:12
반응형

자바 스크립트 콜백 범위


콜백 함수에서 내 개체를 참조 할 때 일반 오래된 JavaScript (프레임 워크 없음)에 문제가 있습니다.

function foo(id) {
    this.dom = document.getElementById(id);
    this.bar = 5;
    var self = this;
    this.dom.addEventListener("click", self.onclick, false);
}

foo.prototype = {
    onclick : function() {
        this.bar = 7;
    }
};

이제 새 개체를 만들 때 (DOM이로드 된 후 span # test를 사용하여)

var x = new foo('test');

onclick 함수 내부의 'this'는 foo 객체가 아닌 span # test를 가리 킵니다.

onclick 함수 내에서 foo 객체에 대한 참조를 얻으려면 어떻게해야합니까?


(다른 답변의 주석에 숨겨진 일부 설명을 추출했습니다)

문제는 다음 줄에 있습니다.

this.dom.addEventListener("click", self.onclick, false);

여기서는 콜백으로 사용할 함수 객체를 전달합니다. 이벤트 트리거가 발생하면 함수가 호출되지만 이제는 개체와 연결되지 않습니다 (this).

이 문제는 다음과 같이 클로저에 함수 (객체 참조 포함)를 래핑하여 해결할 수 있습니다.

this.dom.addEventListener(
  "click",
  function(event) {self.onclick(event)},
  false);

변수 자체가 할당 된 이후 폐쇄을 만들 때 그것이 나중에라고 할 때, 폐쇄 기능은 자기 변수의 값을 기억합니다.

이를 해결하는 또 다른 방법은 유틸리티 함수를 만드는 것입니다 (그리고 이것을 바인딩 하기 위해 변수를 사용하지 마십시오 ) :

function bind(scope, fn) {
    return function () {
        fn.apply(scope, arguments);
    };
}

업데이트 된 코드는 다음과 같습니다.

this.dom.addEventListener("click", bind(this, this.onclick), false);

Function.prototype.bindECMAScript 5의 일부이며 동일한 기능을 제공합니다. 따라서 다음을 수행 할 수 있습니다.

this.dom.addEventListener("click", this.onclick.bind(this), false);

아직 ES5를 지원하지 않는 브라우저의 경우 MDN은 다음 shim을 제공합니다 .

if (!Function.prototype.bind) {  
  Function.prototype.bind = function (oThis) {  
    if (typeof this !== "function") {  
      // closest thing possible to the ECMAScript 5 internal IsCallable function  
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");  
    }  

    var aArgs = Array.prototype.slice.call(arguments, 1),   
        fToBind = this,   
        fNOP = function () {},  
        fBound = function () {  
          return fToBind.apply(this instanceof fNOP  
                                 ? this  
                                 : oThis || window,  
                               aArgs.concat(Array.prototype.slice.call(arguments)));  
        };  

    fNOP.prototype = this.prototype;  
    fBound.prototype = new fNOP();  

    return fBound;  
  };  
} 

this.dom.addEventListener("click", function(event) {
    self.onclick(event)
}, false);

를 들어 jQuery를에 이 문제에 대한 해결책을 찾는 사용자, 당신은 사용해야합니다 jQuery.proxy을


The explanation is that self.onclick does not mean what you think it means in JavaScript. It actually means the onclick function in the prototype of the object self (without in any way referencing self itself).

JavaScript only has functions and no delegates like C#, so it is not possible to pass a method AND the object it should be applied to as a callback.

The only way to call a method in a callback is to call it yourself inside a callback function. Because JavaScript functions are closures, they are able to access the variables declared in the scope they were created in.

var obj = ...;
function callback(){ return obj.method() };
something.bind(callback);

A good explanation of the problem (I had problems understanding solutions described so far) is available here.


I wrote this plugin...

i think it will be useful

jquery.callback


this is one of the most confusing points of JS: the 'this' variable means to the most local object... but functions are also objects, so 'this' points there. There are other subtle points, but i don't remember them all.

I usually avoid using 'this', just define a local 'me' variable and use that instead.

참고URL : https://stackoverflow.com/questions/183214/javascript-callback-scope

반응형