krave
krave

Reputation: 1919

What does this in this snippet?

I am reading You Don't Know JS: ES6 & Beyond and I encountered this snippet in Symbol.species section.

class Cool {
    // defer `@@species` to derived constructor
    static get [Symbol.species]() { return this; }

    again() {
        return new this.constructor[Symbol.species]();
    }
}

class Fun extends Cool {}

class Awesome extends Cool {
    // force `@@species` to be parent constructor
    static get [Symbol.species]() { return Cool; }
}

var a = new Fun(),
    b = new Awesome(),
    c = a.again(),
    d = b.again();

c instanceof Fun;           // true
d instanceof Awesome;       // false
d instanceof Cool;          // true

It seems like the function Symbol.species{ return Something } should always return a constructor function. But in the first presence of this function: static get [Symbol.species]() { return this; } I am confused because I always think this should be an object instead of a constructor function. Could you please help me to clarify the facts?

And about return new this.constructor[Symbol.species]();, what does this here refer to?

Upvotes: 6

Views: 159

Answers (1)

Patrick Evans
Patrick Evans

Reputation: 42736

this will refer to something different inside a method depending on the context it was executed.

In class methods, static methods, this will refer to the class.

So for instance with

static get [Symbol.species]() { return this; }

Since this is a class method, it will is executed on the class and this will refer to the class

//since this is a getter we don't use trailing `()`
Cool[Symbol.species] === Cool;
//It does not exist on instances
var myCool = new Cool();
console.log( myCool[Symbol.species] );
//will give undefined

Now for instance methods, like the again method, they only exist on the instance and so are called from the instance and not the class:

console.log( Cool.again );
//will give undefined
var myCool = new Cool();
var newInstance = myCool.again();

In instance methods this refers to the instance, not the class.

So given:

 return new this.constructor[Symbol.species]();
  • this is the instance (eg, new Cool)
  • this.constructor is the constructor that created the instance (eg, Cool)
  • this.constructor[Symbol.species] is the class getter method Symbol.species
  • new this.constructor[Symbol.species]() is a new instance of the class that Symbol.species returned

So the whole line is returning a new instance of a class that the static getter Symbol.species method returns.

This allows a class to have methods that create new instances of a class without knowing its name.

So as the example shows, even though Fun never defined it's own again method again knows how to create a new instance of Fun. And as Awesome shows you can just override Symbol.species to change what instance again will create.

Upvotes: 5

Related Questions