3

I was searching and can't find a proper way to figure out this in ES6 way.

class MyClass {
  // i can't event decalre _this/_self here
  constructor() {
     setTimeout(function(){
        // other work..
        hiUser(); // this.hiUser() or //_this.hiUser() not working
     },1000);
   }
   hiUser(){
     alert('Hi');
   }
}
sdgluck
  • 24,894
  • 8
  • 75
  • 90
dev.meghraj
  • 8,542
  • 5
  • 38
  • 76
  • If you were going to set `self` you'd do it inside the constructor, not inside the class. But just use an arrow function like @Buzinas said. – JMM Oct 01 '15 at 16:03

3 Answers3

10

The previous answers only gave you code samples on how to fix it; Let me explain your issue and why it's happening

In your code example, the function inside of your setTimeout is being bound to the this value of the setTimeout (which is generally window or undefined in strict mode).

setTimeout(function () {
    // this === window
}, 1000);

In ES6, they introduced lambda expressions (arrow functions) which are "lexically bound" -- meaning that they borrow the this value from their outside scope. In your case, that's the class/object.

In order to leverage the lambda expressions, it would look like:

class Foo {

    constructor () {
        setTimeout(() => this.myMethod(), 1000);
    }

    myMethod () {
        console.log('foo');
    }
}

If you're using Babel to transpile your code, and are using experimental features, you can use ES7's binding syntax to solve your problem as well.

If you bind a function/method, it creates a copy of that function, and binds the this value to whatever you choose. This will allow you to use the function statement that will be bound to your class/object.

<context to be bound> :: <function to receive context>

class Foo {

    constructor () {
        setTimeout(this::function() {
            this.myMethod();
        }, 1000);
    }

    myMethod () {
        console.log('foo');
    }
}

An even shorter version would look something like the following

constructor () {
    setTimeout(this::this.myMethod, 1000);
}

If you're still having issues understanding this, I suggest you read more about ES6 classes and javascript binding.

ndugger
  • 7,373
  • 5
  • 31
  • 42
  • Please stop calling them "fat arrow" functions. This is a leftover from coffeescript. They're just [arrow functions](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-arrow-function-definitions). – Mulan Oct 01 '15 at 16:47
  • @naomik I prefer to call them lambdas; I just use arrow functions to make sure that people know what I'm referring to. – ndugger Oct 01 '15 at 16:56
  • Sure, "lambda", "anonymous function", "closure", whatever. If you read the spec I linked, ECMAScript calls them "arrow functions". My point is you didn't call them "arrow functions", you called them "**fat** arrow functions", which is coffeescript lingo. – Mulan Oct 01 '15 at 17:01
  • Yeah, I usually don't -- it was in my head after reading the other answer here. – ndugger Oct 01 '15 at 17:06
3

You can use fat arrow functions:

class MyClass {
  constructor() {
    setTimeout(() => {
      this.hiUser();
    }, 1000);
  }

  hiUser(){
    alert('Hi');
  }
}

Or you can use the simple ES5's Function.prototype.bind method:

class MyClass {
  constructor() {
    setTimeout(function() {
      this.hiUser();
    }.bind(this), 1000);
  }

  hiUser(){
    alert('Hi');
  }
}

There is an ES7 proposal to shorthand the Function.prototype.bind method, so, depending on the transpiler (e.g Babel or Typescript) you're (possibly) using, you can set the ES7 flags and use it today:

class MyClass {
  constructor() {
    setTimeout(::function() {
      this.hiUser();
    }, 1000);
  }

  hiUser(){
    alert('Hi');
  }
}
Buzinas
  • 11,597
  • 2
  • 36
  • 58
  • i don't just want to call hiUser i also need a function where i can do other things as well. – dev.meghraj Oct 01 '15 at 15:58
  • @dev.mraj You can just use curly brackets and put whatever you want. I've updated my answer. – Buzinas Oct 01 '15 at 16:00
  • Thanks for fat arrow functions.... great. – dev.meghraj Oct 01 '15 at 16:02
  • @X.L.Ant because if you bind the method inside of the timeout, "this" is already something else – ndugger Oct 01 '15 at 16:03
  • @X.L.Ant according to the OP, he wants to put more code inside the function, not only calling `this.hiUser`. – Buzinas Oct 01 '15 at 16:03
  • @Buzinas you should add an example using ES7's "::" bind syntax (`this::setTimeout( ... );`) – ndugger Oct 01 '15 at 16:03
  • Also, I would remove that last example, because now, in the hiUser method, 'this' no longer refers to the class (which is generally a bad idea). I would stick with the lambda. – ndugger Oct 01 '15 at 16:08
  • 1
    @Nick Alright, done! :) – Buzinas Oct 01 '15 at 16:09
  • @dev.mraj if my answer was useful to you, please mark it as the accepted! :) – Buzinas Oct 01 '15 at 16:13
  • 2
    Please stop calling them "fat arrow" functions. This is a leftover from coffeescript. They're just [arrow functions](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-arrow-function-definitions). – Mulan Oct 01 '15 at 16:47
  • 1
    For people coming to this via the route I did, which was figuring out why "this" wasn't behaving properly, I found this section specifically helpful from the first link in this answer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this "An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope, an arrow function ends up finding the this from its enclosing scope." – streetlogics Oct 22 '19 at 20:58
-1

setTimeout might have its own this context. You could set _self in the constructor though, or use arrow functions:

class MyClass {
    constructor () {
        var self = this;
        // etc.
    }
}
Adam Kewley
  • 1,224
  • 7
  • 16