Ссылка на "this" внутри setInterval/setTimeout в методах прототипа объекта

Обычно я назначаю альтернативную ссылку "self", когда ссылаюсь на "this" внутри setInterval. Можно ли сделать что-то подобное в контексте прототипа? Следующие ошибки кода.

function Foo() {}
Foo.prototype = {
    bar: function () {
        this.baz();
    },
    baz: function () {
        this.draw();
        requestAnimFrame(this.baz);
    }
};

Ответ 1

В отличие от языка, такого как Python, метод Javascript забывает, что это метод после его извлечения и передачи его в другом месте. Вы можете либо

Оберните вызов метода внутри анонимной функции

Таким образом, доступ к свойству baz и его вызов происходит в одно и то же время, что необходимо для правильной установки this внутри вызова метода.

Вам нужно будет сохранить this из внешней функции в вспомогательной переменной, так как внутренняя функция будет ссылаться на другой объект this.

var that = this;
setInterval(function(){
    return that.baz();
}, 1000);

Оберните вызов метода внутри функции толстой стрелки

В реализациях Javascript, которые реализуют функцию arrow функции, можно написать вышеприведенное решение более кратким образом, используя стрелку жира синтаксис:

setInterval( () => this.baz(), 1000 );

Анонимные функции Fat arrow сохраняют this от окружающей функции, поэтому нет необходимости использовать трюк var that = this. Чтобы узнать, можете ли вы использовать эту функцию, обратитесь к таблице совместимости, например этот.

Используйте функцию привязки

Конечной альтернативой является использование функции, такой как Function.prototype.bind или эквивалента из вашей любимой библиотеки JavaScript.

setInterval( this.baz.bind(this), 1000 );

//dojo toolkit example:
setInterval( dojo.hitch(this, 'baz'), 100);

Ответ 2

i сделал прокси-класс:)

function callback_proxy(obj, obj_method_name)
{
    instance_id = callback_proxy.instance_id++;
    callback_proxy.instances[instance_id] = obj;
    return eval('fn = function() { callback_proxy.instances['+instance_id+'].'+obj_method_name+'(); }');
}
callback_proxy.instance_id = 0;
callback_proxy.instances = new Array();

function Timer(left_time)
{
    this.left_time = left_time; //second
    this.timer_id;

    this.update = function()
    {
        this.left_time -= 1;

        if( this.left_time<=0 )
        {
            alert('fin!');
            clearInterval(this.timer_id);
            return;
        }
    }

    this.timer_id = setInterval(callback_proxy(this, 'update'), 1000);
}

new Timer(10);