JavaScript: когда B наследует от A, обратные вызовы в A не могут видеть B - PullRequest
0 голосов
/ 11 декабря 2010

Невозможно понять, как получить доступ к «расширенным» свойствам дочернего объекта из обратного вызова в родительском объекте. Мои две попытки ниже. Я хотел бы, чтобы функция «say_something» оповещала «скажи привет», где «привет» происходит от ребенка. Вместо этого он говорит «скажи неопределенный».

Попытка 1: я создаю объект «а», а затем создаю новый объект «б», производный от него. Но обратный вызов в «a» (здесь из setTimeout) не будет иметь доступа к правильному «this».

var a = {};
a.say_something = function () { setTimeout( function () { alert( "say " + this.text ); }, 0 ); };

var b = Object.create( a );
b.text = "hi";

b.say_something(); // alerts "say undefined"

Попытка 2: Распространенная мудрость гласит, что необходимо перестроить, чтобы учесть «ту» переменную, к которой можно получить доступ в обратном вызове. Но в отличие от «this», «that» не может получить доступ к свойствам из «b»:

var a = ( function () {
    var that = {};
    that.say_something = function () { setTimeout( function () { alert( "say " + that.text ); }, 0 ); };
    return that;
}() );

var b = ( function () {
    var that = Object.create( a );
    that.text = "hi";
    return that;
}() );

b.say_something(); // alerts "say undefined"

PS, я использую функцию Object.create Дугласа Крокфорда вместо (смущает меня) new (). Копируется здесь:

if ( typeof Object.create !== "function" ) {
    Object.create = function ( o ) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Ответы [ 2 ]

2 голосов
/ 11 декабря 2010

Если вы добавите

a.say_something();

в первом примере он также вернет say undefined. Проблема в том, что setTimeout не выполняет код, который он вызывает, в области, в которой он вызывается.

Мы можем решить это либо:

  1. Жесткое кодирование ссылки на существующий объект alert('say ' + a.text);
  2. Использование call() и apply() для указания контекста, в котором должна выполняться функция. (И bind() тоже - для новейших платформ.)

Подход №2 - это то, что вы ищете.

var a = {};
a.text = "hello!";
function say_something() {
    var that = this; // Save the reference to *this* this.
    setTimeout( function() { console.log.call(that, "say " + that.text ); }, 0 ); 
}
a.say_something = say_something;
a.say_something(); // say hello!

var b = ( function () {
    var that = Object.create( a );
    that.text = "hi there!";
    return that;
}() );

b.say_something(); // say hi there!
2 голосов
/ 11 декабря 2010

В функции setTimeout «this» всегда относится к объекту Window.

Я обычно делаю что-то вроде (протестировано и работает)

a.say_something = function () {
    var thisObj = this;
    setTimeout(function () { 
        alert( "say " + thisObj.text ); 
    }, 0 ); 
};
...