올바른 "this"컨텍스트를 setTimeout 콜백에 전달 하시겠습니까?


250

컨텍스트를 setTimeout어떻게 전달 합니까? 내가 전화 할 this.tip.destroy()경우 this.options.destroyOnHide이후 1000 밀리. 어떻게해야합니까?

if (this.options.destroyOnHide) {
     setTimeout(function() { this.tip.destroy() }, 1000);
} 

위를 시도 this하면 창을 참조하십시오.


4
중복 플래그가 실제로 유효합니까? 이 질문은 실제로 이전에 요청되었습니다.
Sui Dream

1
if (this.options.destroyOnHide) {setTimeout (function () {this.tip.destroy ()} .bind (this), 1000); }
Zibri

답변:


352

편집 : 요약하면,이 질문이 제기 된 2010 년 에이 문제를 해결하는 가장 일반적인 방법 은 전역 객체 를 가리키는 함수를 실행 setTimeout하기 때문에 함수 호출이 수행 되는 컨텍스트에 대한 참조를 저장하는 것이 었습니다 .setTimeoutthis

var that = this;
if (this.options.destroyOnHide) {
     setTimeout(function(){ that.tip.destroy() }, 1000);
} 

그 전에 1 년 전에 릴리스 된 ES5 사양에서는이 bind방법을 도입했습니다.이 방법 은 아직 널리 지원되지 않았고 사용하기 위해 폴리 필이 필요했지만 지금은 어디에나 있기 때문에 원래 답변에서 제안되지 않았습니다.

if (this.options.destroyOnHide) {
     setTimeout(function(){ this.tip.destroy() }.bind(this), 1000);
}

bind함수는 this값이 미리 채워진 새 함수를 만듭니다 .

이제 현대 JS에서 이것은 화살표 기능이 ES6 에서 해결하는 문제입니다 .

if (this.options.destroyOnHide) {
     setTimeout(() => { this.tip.destroy() }, 1000);
}

화살표 함수는 this자체 값을 갖지 않으며 , 액세스 할 때 포함 this어휘 범위 의 값에 액세스합니다 .

HTML5는 2011 년에 타이머를 다시 표준화 했으며 이제 콜백 함수에 인수를 전달할 수 있습니다.

if (this.options.destroyOnHide) {
     setTimeout(function(that){ that.tip.destroy() }, 1000, this);
}

또한보십시오:


3
효과가있다. jsbin 스크립트를 사용하여 개념을 테스트했습니다. jsbin.com/etise/7/edit
John K

1
이 코드에는 함수 전체 범위가있는 불필요한 변수를 만드는 것이 포함됩니다. this함수 에 올바르게 전달 하면이 코드, map (), forEach () 등의 코드, CPU 사이클 및 메모리를 사용 하여이 문제를 해결했을 것입니다. *** 참조 : Misha Reyzlin의 답변.
HoldOffHunger

222

@CMS가 응답 한 함수 래퍼에 대한 바로 가기 (구문 설탕)가 있습니다. (아래에서 원하는 컨텍스트가 있다고 가정하십시오 this.tip.)


ECMAScript 5 ( 현재 브라우저 , Node.js) 및 Prototype.js

ECMA-262, 5 판 (ECMAScript 5) 또는 Node.js 와 호환되는 브라우저 를 대상으로하는 경우을 사용할 수 있습니다 Function.prototype.bind. 선택적으로 함수 인수를 전달하여 부분 함수 를 작성할 수 있습니다 .

fun.bind(thisArg[, arg1[, arg2[, ...]]])

다시, 귀하의 경우, 이것을 시도하십시오 :

if (this.options.destroyOnHide) {
    setTimeout(this.tip.destroy.bind(this.tip), 1000);
}

프로토 타입 (다른 라이브러리) 에서도 동일한 기능이 구현 되었습니다 .

Function.prototype.bind사용자 정의 이전 버전과의 호환성을 원할 경우 이와 같이 구현할 수 있습니다 (하지만 참고 사항을 준수하십시오)


ECMAScript 2015 ( 일부 브라우저 , Node.js 5.0.0+)

최첨단 개발 (2015)의 경우에는 사용 지방 화살표 함수 이며, ECMA 스크립트 2,015 (조화 / ES6 / ES2015) 사양의 일부 ( ).

화살표 함수식 (라고도 지방 화살표 함수 ) 함수식에 비해 짧은 구문 및 어휘 바인드 this값 [...]가.

(param1, param2, ...rest) => { statements }

귀하의 경우 다음을 시도하십시오.

if (this.options.destroyOnHide) {
    setTimeout(() => { this.tip.destroy(); }, 1000);
}

jQuery

이미 jQuery 1.4 이상을 사용하고 있다면, 함수의 this컨텍스트 를 명시 적으로 설정하기위한 기성 함수 가 있습니다.

jQuery.proxy () : 함수를 가져 와서 항상 특정 컨텍스트를 갖는 새로운 함수를 반환합니다.

$.proxy(function, context[, additionalArguments])

귀하의 경우 다음을 시도하십시오.

if (this.options.destroyOnHide) {
    setTimeout($.proxy(this.tip.destroy, this.tip), 1000);
}

Underscore.js , lodash

Underscore.js와 lodash뿐만 아니라 1 , 2 에서 사용할 수 있습니다_.bind(...)

bind 함수를 객체에 바인딩 합니다. 즉, 함수가 호출 될 때마다 값이this객체가됩니다. 선택적으로 인수를 함수에 바인드하여 부분 애플리케이션이라고도합니다.

_.bind(function, object, [*arguments])

귀하의 경우 다음을 시도하십시오.

if (this.options.destroyOnHide) {
    setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}


왜 기본값이 func.bind(context...)아닙니까? 내가 뭔가를 그리워합니까?
aTei

이것을 호출 할 때마다 지속적으로 새로운 함수 (바인드가 수행하는)를 계속 만드는 것이 성능이 있습니까? 모든 키를 누른 후에 재설정되는 검색 시간 초과가 있으며 재사용을 위해이 '바운드'방법을 캐싱 해야하는 것처럼 보입니다.
Triynko

@ Triynko : 비싼 연산으로 함수 바인딩을 보지 못하지만 동일한 바인딩 함수를 여러 번 호출하면 참조를 유지할 수도 있습니다 var boundFn = fn.bind(this); boundFn(); boundFn();.
Joel Purra

30

Internet Explorer 이외의 브라우저에서는 지연 후 매개 변수를 함수에 함께 전달할 수 있습니다.

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

그래서 당신은 이것을 할 수 있습니다 :

var timeoutID = window.setTimeout(function (self) {
  console.log(self); 
}, 500, this);

이것은 (캐시 룩업 범위보다 성능면에서 더 this제한 시간 / 간격 식의 변수의 외부로) 후 (사용하여 고정을 생성 $.proxy하거나 Function.prototype.bind).

Webreflection의 IE에서 작동하도록하는 코드 :

/*@cc_on
(function (modifierFn) {
  // you have to invoke it as `window`'s property so, `window.setTimeout`
  window.setTimeout = modifierFn(window.setTimeout);
  window.setInterval = modifierFn(window.setInterval);
})(function (originalTimerFn) {
    return function (callback, timeout){
      var args = [].slice.call(arguments, 2);
      return originalTimerFn(function () { 
        callback.apply(this, args) 
      }, timeout);
    }
});
@*/

1
프로토 타입 체인을 사용하여 클래스를 작성하고 메소드가 프로토 타입 메소드 인 경우 '바인드'만이 메소드 내의 '이것'을 변경하는 유일한 것입니다. 콜백에 매개 변수를 전달하면 함수에서 'this'가 무엇인지 변경하지 않으므로 다른 프로토 타입 메서드에서와 같이 'this'를 사용하여 이러한 프로토 타입 함수를 작성할 수 없습니다. 불일치가 발생합니다. 바인드는 우리가 실제로 원하는 것과 가장 가까운 것이므로 클로저는 더 높은 조회 성능을 위해 한 번 이상 만들 필요없이 'this'로 캐싱 될 수 있습니다.
Triynko

3

참고 : 이것은 IE에서 작동하지 않습니다

var ob = {
    p: "ob.p"
}

var p = "window.p";

setTimeout(function(){
    console.log(this.p); // will print "window.p"
},1000); 

setTimeout(function(){
    console.log(this.p); // will print "ob.p"
}.bind(ob),1000);

2

을 사용하는 경우을 사용할 underscore수 있습니다 bind.

예 :

if (this.options.destroyOnHide) {
     setTimeout(_.bind(this.tip.destroy, this), 1000);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.