35

I am running the below code in nodejs

this.x = 'global x';
class Point {
    constructor(x) {
        this.x = x;
    }
    toString() {
        return this.x;
    }
}
var obj = new Point(1);
obj.toString();// 1 as expected
var a = obj.toString;// Here I can do something like var a = obj.toString.bind(obj); to get rid of the situation. But I am curious to know how can we write `var self = this`;
a();// TypeError: Cannot read property 'x' of undefined

a(); throws the error.
How can we do like var self = this; as we used to do in es5 to prevent such a situation?

intekhab
  • 1,566
  • 1
  • 13
  • 19
  • What are you trying to do with your first line this.x = 'global x'; ? – Roumelis George Sep 15 '15 at 10:14
  • @Roumelis I was expecting `a()` will run in global code and `toString()` is returning `this.x` so `a()` will return `global x` – intekhab Sep 15 '15 at 10:16
  • You are adding x in window on purpose then? – Roumelis George Sep 15 '15 at 10:17
  • Yea I thought something like that. But this will be my another query what happens in nodejs when we write `this.x` globally. Code runs fine when we write globally `this.x = 'something'`. `get(this.x);` outputs `'something'` – intekhab Sep 15 '15 at 10:19
  • 1
    You are doing it exactly the same way. Nothing changed in that regard in ES6 (except you also have arrow functions). It's unclear to me how you would use `var self = this` without classes to begin with... – Felix Kling Sep 15 '15 at 13:37
  • Never mix lexical and contextual scopes in JS. Use .bind or arrow functions. – Rafael Hovsepyan Jan 12 '18 at 09:49

2 Answers2

28

How can we do like var self = this; as we used to do in ES5?

You can do it exactly like you did in ES5 - ES6 is completely backward-compatible after all:

class Point {
    constructor(x) {
        this.x = x;
        var self = this;
        this.toString = function() {
            return self.x;
        };
    }
}

However, that's really not idiomatic ES6 (not talking about const instead of var). You'd rather use an arrow function that has a lexical-scoped this, so that you can avoid this self variable completely:

class Point {
    constructor(x) {
        this.x = x;
        this.toString = () => {
            return this.x;
        };
    }
}

(which could even be shortened to this.toString = () => this.x;)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • if I put this code `this.toString = function() { return self.x; };` out of constructor like this `toString() { return self.x; };` as we can do this, In this case self is `undefined` and throw error – intekhab Sep 16 '15 at 04:33
  • 1
    @intekhab: Yes of course it is - `self` is a variable scoped to the constructor. As I said, it works just like in ES5. The new ES6 `class` syntax introduces hardly anything new but the *syntax*. – Bergi Sep 16 '15 at 07:57
16

If you don't want to create all your class methods inside the constructor as Bergi suggests (which seems ugly to me) then you can enable ES7 features and define your method using arrow syntax:

class Point 
{
    constructor(x) 
    {
        this.x = x;
    }

    toString = () =>  
    {
        return this.x;
    }
} 

This has the same effect as saying:

constructor(x)
{
    this.toString = this.toString.bind(this);
}

But it still doesn't allow you to access the dynamic this and the lexical this (self) in the same function. So this is not a complete answer.

I hope someone can edit this answer to show how we can access both types of this in a class method without defining every method in the class constructor.

Richard
  • 14,798
  • 21
  • 70
  • 103
  • 4
    Well, this still does create all your methods inside the constructor (and is just as ugly), only it uses an experimental syntax for it. – Bergi Nov 06 '15 at 12:58