2013-05-25 3 views
-1
var i=0; 
var t={ 
    a:function(){ 
    this.timer=setInterval(this.b,30); 
    }, 
    b:function(){ 
    if(i++<1){ 
     console.log(this); 
    } 
    } 
}; 
t.a(); 

Почему я получил [круглый объект global]? Я хочу, чтобы «это» относится к объекту t;SetInterval с областью действия в javascript

Как я могу это получить?

И я знаю, как решить эту проблему, следующие коды прав результат:

var i=0; 
var t={ 
    a:function(){ 
    var that=this; 
    this.timer=setInterval(function(){ 
     that.b(); 
    },30); 
    }, 
    b:function(){ 
    if(i++<1){ 
     console.log(this); 
    } 
    } 
}; 
t.a(); 
+3

Итак, если вы знаете, как исправить проблему ... почему вы спрашиваете? – migg

+1

@migg я хочу знать почему :) – Fakefish

+0

Не путайте * context * ('thisArg') с [variable] * scope * – Bergi

ответ

2

Вам нужно либо использовать Function.prototype.bind или Function.prototype.call переназначить контекст, как функция, вызываемая таким образом теряет это контекст к глобальному охвату. Это наиболее легко наблюдать в следующем примере

o = { // an object 
    foo: 1, 
    bar: function() { // function assuming `this` is `o` 
     return this.foo; 
    } 
}; 
f = o.bar; // function `f` loses scope of `o` 
o.bar(); // 1,   o.foo is defined 
f();  // undefined, window.foo is undefined 

Вот некоторые примеры решения в вашем случае

// bind 
function scopedInterval(func, delay, context) { 
    return window.setInterval(func.bind(context), delay); 
} 
// or call 
function scopedInterval(func, delay, context) { 
    return window.setInterval(function() {func.call(context);}, delay); 
} 

В этих примерах, вы бы передать this в качестве 3-го параметра, т.е.

this.timer = scopedInterval(this.b, 30, this); 

Если вы не сделаете этого, контекст setIntervalwindow (я всегда призываю его как window.setInterval, так что я не забуду)

+0

спасибо, я понимаю – Fakefish

+0

это не объясняет почему. И причина в том, что это ошибка в языке –

+1

@ Geeo Единственная причина, по которой я не могу ответить +1 (как вы повторили в своем комментарии), вы говорите: «Это ошибка языка». Это мнение, и пока я согласен, что _JavaScript_ имеет глупые определения того, как «это» должно работать в этих случаях, и это может «обмануть людей», я не считаю это «ошибкой». –

0

Как говорит Крокфорд в своей удивительной книге: «Javascripts: The Good Parts»:

Когда функция не является собственностью объект, то он вызывается как функция [это имеет значение setInterval]. Когда функция вызывается с помощью этого шаблона, «это» привязано к глобальному объекту. Это было ошибкой в ​​оформлении языка. Если бы язык был спроектирован правильно, когда вызывается внутренняя функция, «это» все равно будет привязано к «этой» переменной внешней функции. Следствием этой ошибки является то, что метод не может использовать внутреннюю функцию, чтобы помочь ей выполнять свою работу, потому что внутренняя функция не разделяет доступ метода к объекту, поскольку его «это» связано с неправильным значением. [Затем он говорит об обходном методе, который тот же, что вы нашли].,

Вы правы, задаваясь вопросом, почему это не сработает, и для меня все остальные ответы не соответствуют этому должным образом. На самом деле это бессмысленно, и, поскольку Крокфорд говорит, что это ошибка в дизайне языка, и это может быть довольно запутанным.

+0

спасибо, я еще не прочитал эту книгу, я скоро прочитаю удивительную книгу! – Fakefish

+0

Правильно, что «this' не должен ссылаться на глобальный объект, но я думаю, что это вызовет всевозможные странности, если бы« это »должно было ссылаться на то, что было в лексически закрывающей области, когда эта функция была создана. – Pointy

+0

@ Вы можете подробно рассказать о том, почему вы так думаете? –

Смежные вопросы