Использование bind для гарантии того, что метод ссылается на объект, но, похоже, он не работает - PullRequest
1 голос
/ 15 февраля 2012

Продолжая свои эксперименты в правильном Javascript, я пытаюсь запустить один метод (SayHello) из другого (WaitAndSayHello). Поскольку используется обратный вызов, я использовал bind , чтобы гарантировать, что «this» в каждом методе ссылается на объект.

pretendThingConstructor = function (greeting) {
    this.greeting = greeting;

    this.SayHello = function() {
        console.log(this.greeting); // Works
    };

    this.WaitAndSayHello = function() {
        setTimeout(function() { 
            console.log(this)  
            this.SayHello() // Fails
        }, 500);
    }
    this.WaitAndSayHello.bind(this); // This bind() doesn't seem to work
}


var pretend_thing = new pretendThingConstructor('hello world');
pretend_thing.SayHello();
pretend_thing.WaitAndSayHello();

Код выводит «hello world», затем завершается с ошибкой «Object # не имеет метода« SayHello »» во второй раз. Из console.log я вижу, что «this» относится к событию. Однако не следует использовать bind (), чтобы это исправить?

Как я могу заставить работать bind ()?

Кроме того, я хотел бы сделать это чисто: т.е. без ссылки на название объекта в нескольких местах.

Ответы [ 2 ]

5 голосов
/ 15 февраля 2012

Вы не можете "поздний звонок" .bind(). Вы должны вызвать его во время объявления функции, например

this.WaitAndSayHello = function() {
    setTimeout(function() { 
        console.log(this)  
        this.SayHello() // Fails
    }, 500);
}.bind(this)

Кроме того, анонимная функция, которую вы передаете в setTimeout(), создает новый контекст и, следовательно, имеет свое собственное значение this context.

Вам либо нужно хранить ссылку на "external this" в такой переменной, как

this.WaitAndSayHello = function() {
    var self = this;

    setTimeout(function() { 
        console.log(self)  
        self.SayHello() // succeeds
    }, 500);
}.bind(this)

или используйте .bind() снова, как

this.WaitAndSayHello = function() {
    setTimeout(function() { 
        console.log(this)  
        this.SayHello() // succeeds
    }.bind(this), 500);
}.bind(this)
1 голос
/ 15 февраля 2012

вы должны использовать:

this.WaitAndSayHello.call(this);

или

this.WaitAndSayHello.apply(this);

Разница между apply и call заключается в способе передачи аргументов вызываемой функции: представьте, WaitAndSayHello получил несколько аргументов:

this.WaitAndSayHello = function(toWho, helloMessage){
 ...
}

с call, вы будете передавать аргументы после контекста, как обычно вызываете функцию:

this.WaitAndSayHello.call(this, 'Bob', 'Hello');

с apply вы должны передать аргументы в виде массива:

this.WaitAndSayHello.apply(this, ['Bob', 'Hello']);

Редактировать

Извините, я неправильно прочитал ваш код, @ jAndy's действительно правильный, но, используя мою логику, вы могли бы сделать что-то вроде:

this.WaitAndSayHello = function() {
        setTimeout.call(this, function() { 
            console.log(this)  
            this.SayHello() // Fails
        }, 500);
    }
...