Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create a class that does not inherit from Object.prototype using ES6 classes?

I can create a class that does not inherit from Object.prototype using the older syntax.

function Shape(x, y, width, height) {
  this.x = x,
  this.y = y,
  this.width = width,
  this.height = height;
}

Shape.prototype = Object.create(null, {
  constructor: {
    configurable: true,
    writable: true,
    value: Shape
  },
  move: {
    configurable: true,
    writable: true,
    value: function (x, y) {
      this.x += x,
      this.y += y;
    }
  }
});

var rect = new Shape(0, 0, 4, 2);
console.log(Object.getPrototypeOf(rect) === Shape.prototype);
console.log(Object.getPrototypeOf(Object.getPrototypeOf(rect)) !== Object.prototype); //inheritance

How can I do this using ES6 classes?

class Shape {
  constructor(x, y, width, height) {
    this.x = x,
    this.y = y,
    this.width = width,
    this.height = height;
  }

  move(x, y) {
    this.x += x,
    this.y += y;
  }
}

var rect = new Shape(0, 0, 4, 2);
console.log(Object.getPrototypeOf(rect) === Shape.prototype);
console.log(Object.getPrototypeOf(Object.getPrototypeOf(rect)) === Object.prototype); // inheritance
like image 677
Michael Theriot Avatar asked Mar 11 '16 04:03

Michael Theriot


People also ask

Which keyword can be used to implement inheritance in ES6?

We use the extends keyword to implement the inheritance in ES6. The class to be extended is called a base class or parent class.

Does ES6 use prototype?

The prototype property allows you to add properties and methods to any object (Number, Boolean, String and Date, etc.). Note − Prototype is a global property which is available with almost all the objects. Use the following syntax to create a Boolean prototype.

Which JavaScript feature is the alternative to the ES6 classes the class keyword )?

The function keyword is replaced with the class keyword. There's a special function named 'constructor' where the initialization of the object is done.


2 Answers

You can use extends null.

Note the class itself will still inherit from Function.prototype, not from null. So you will be able to use function methods on the class.

But be aware that, when using an extends clause, you must either initialize this before using it by calling super, or don't use this and return an object at the end.

In this case you can't initialize this using super because Function.prototype is not a constructor. So you will have to use Object.create to create the object that will become the instance.

class Shape extends null {
  constructor(x, y) {
    // Use `that` instead of `this`, and return it at the end
    var that = Object.create(new.target.prototype);
    that.x = x;
    that.y = y;
    return that;
  }
  move(x, y) {
    this.x += x;
    this.y += y;
  }
}
var rect = new Shape(0, 0);
console.log(rect);
console.log(Object.getPrototypeOf(rect) === Shape.prototype);
console.log(Object.getPrototypeOf(Shape.prototype) === null);
console.log(Object.getPrototypeOf(Shape) === Function.prototype);

new.target will be the function that is being instantiated. This can be Shape itself, or another function that extends it. This is useful to allow Shape to be extendable.

class Shape extends null {
  constructor(x, y) {
    // Use `that` instead of `this`, and return it at the end
    var that = Object.create(new.target.prototype);
    that.x = x;
    that.y = y;
    return that;
  }
  move(x, y) {
    this.x += x;
    this.y += y;
  }
}
class BestShape extends Shape {
  constructor(...args) {
    super(...args);
    this.best = true;
  }
}
var rect = new BestShape(0, 0);
console.log(rect);
console.log(Object.getPrototypeOf(rect) === BestShape.prototype);
console.log(Object.getPrototypeOf(BestShape.prototype) === Shape.prototype);
console.log(Object.getPrototypeOf(Shape.prototype) === null);
console.log(Object.getPrototypeOf(BestShape) === Shape);
console.log(Object.getPrototypeOf(Shape) === Function.prototype);

If you don't want to avoid using this in your constructor, an alternative is extending a function whose prototype is null. The downside is that your class will inherit from that function, instead of directly from Function.prototype.

function NullClass() {}
NullClass.prototype = null;

class Shape extends NullClass {
  constructor(x, y) {
    super();
    this.x = x;
    this.y = y;
  }
  move(x, y) {
    this.x += x;
    this.y += y;
  }
}
var rect = new Shape(0, 0);
console.log(rect);
console.log(Object.getPrototypeOf(rect) === Shape.prototype);
console.log(Object.getPrototypeOf(Shape.prototype) === null);
console.log(Object.getPrototypeOf(Shape) === NullClass);
console.log(Object.getPrototypeOf(NullClass) === Function.prototype);

If you don't want to reuse NullClass, you can define it inline

class Shape extends Object.assign(function(){},{prototype:null}) { /* ... */ }
like image 109
Oriol Avatar answered Sep 20 '22 01:09

Oriol


You will have to manually set Shape.prototype's prototype to null.

class Shape {
  constructor(x, y, width, height) {
    this.x = x,
    this.y = y,
    this.width = width,
    this.height = height;
  }
    
  move(x, y) {
    this.x += x,
    this.y += y;
  }
}

// This is the key line.
Object.setPrototypeOf(Shape.prototype, null);

const rect = new Shape(0, 0, 4, 2);
console.log(Object.getPrototypeOf(rect) === Shape.prototype);
console.log(Object.getPrototypeOf(Object.getPrototypeOf(rect)) !== Object.prototype);
like image 27
Frank Tan Avatar answered Sep 22 '22 01:09

Frank Tan