简体   繁体   中英

Javascript/Typescript 'this' scope

I am working with Ionic2 and Meteor. I do however have a Javascript/Typescript issue relating to the scope of the this object.

I have read that I should use bind when I don't have handle on this at the appropriate level.

I probably don't understand the concept, because I try the following, but get an error trying to call a function.

this.subscribe('messages', this.activeChat._id, this.senderId, () => {
    this.autorun(() => {
        let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
        promiseMessages.then((messageData: Mongo.Collection<Message>) => {
        messageData.find().forEach(function (message: Message) {
            setLocalMessage.bind(message);
        });
    });
});

and

private setLocalMessage(message: Message): void {
   this.localMessageCollection.insert(message);
}

I get the following error when I try build the app:

 ERROR in ./app/pages/messages/messages.ts (72,19): error TS2304: Cannot find name 'setLocalMessage'. 

UPDATE

Thank you for the advise below.

I am now using the following, and it works.

          let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
          promiseMessages.then((messageData: Mongo.Collection<Message>) => {
            messageData.find().forEach((message: Message) => {
              this.setLocalMessage(message);
            });
          });

I have read that I should use bind when I don't have handle on this at the appropriate level.

That's a bit outdated now, better have a look at How to access the correct `this` context inside a callback? these days which also shows you how to use arrow functions.

You're getting the error message because setLocalMessage is not a variable but still a property of this so you have to access it as such. There are basically three solutions in your case:

  • bind

     messageData.find().forEach(this.setLocalMessage.bind(this)); 
  • the context argument of forEach (assuming it's the Array method):

     messageData.find().forEach(this.setLocalMessage, this); 
  • another arrow function:

     messageData.find().forEach((message: Message) => { this.setLocalMessage(message); }); 

There are a few things wrong here.

In ES6 (and thus TypeScript), you need to refer to instance members using explicit this, such as this.setLocalMessage . Just writing setLocalMessage is invalid no matter where the code is.

Inside a function , the this object will probably not be what you expect anyway. You need to capture the this object from outside the function and put it in a variable, like so:

this.subscribe('messages', this.activeChat._id, this.senderId, () => {
    this.autorun(() => {
        let self = this;
        let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
        promiseMessages.then((messageData: Mongo.Collection<Message>) => {
        messageData.find().forEach(function (message: Message) {
            self.setLocalMessage(message);
        });
    });
});

Alternatively, you can use an arrow expression, in which this is the same as what it is in the code around it:

this.subscribe('messages', this.activeChat._id, this.senderId, () => {
    this.autorun(() => {
        let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
        promiseMessages.then((messageData: Mongo.Collection<Message>) => {
        messageData.find().forEach(message => this.setLocalMessage(message));
        });
    });
});

It's not an issue of TypeScript itself. Without it, the code will just fail at runtime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM