secret
Created

  • Download Gist
javascript.markdown
Markdown

JavaScript Class Syntax

Let's build a JavaScript class syntax from first principles. For the purpose of this exercise, let's assume that the purpose of the class syntax is to add much-needed sugar to common JavaScript idioms.

Let's start with how JavaScript "classes" work today:

// this is a constructor
Person = function() {
  this // `this` is a new instance of Person
}

// define a list of properties that exist on all instances of Person
Person.prototype = {
  hello: function(text) {
    this // `this` is the current instance of Person
    console.log(text)
  }
}

Let's add some syntax to JavaScript to represent this idiom:

class Person {
  function constructor() {
    // `this` is a new instance of Person
  }

  function hello(text) {
    // `this` is the current instance of Person
    console.log(text)
  }
}

The class is simply the constructor function with the remaining functions assigned to its prototype. If no constructor function is supplied, an empty function is used.

For a dash of sugar, we can allow the word function to be left out:

class Person {
  constructor() {
    // `this` is a new instance of Person
  }

  hello(text) {
    // `this` is the current instance of Person
    console.log(text)
  }
}

Now let's look at inheritance:

// this is a constructor
Man = function() {
  Person.apply(this, arguments) // invoke the superclass constructor

  this // `this` is a new instance of Man
}

// subclass Person
Man.prototype = Object.create(Person);

// create a new method called fullName
Man.prototype.fullName = function() {
  return "Mr. " + this.firstName + ' ' + this.lastName;
}

// subclass `hello` and invoke the superclass
Man.prototype.hello = function(text) {
  Person.prototype.hello.call(this, this.fullName() + " says: " + text);
}

Let's add some syntax to JavaScript to represent this idiom:

// same as Man.prototype = Object.create(Person)
class Man extends Person {
  // using ES.next rest arguments syntax
  constructor(...args) {
    super(...args) // same as Person.apply(this, arguments)
  }

  fullName() {
    return "Mr. " + this.firstName + ' ' + this.lastName;
  }

  hello(text) {
    // same as Person.prototype.hello.apply(this, [...args])
    super(this.fullName() + " says: " + text);
  }
}

The super keyword simply invokes a function of the same name on the direct superclass of the current object's constructor, passing along any arguments passed.

Finally, people sometimes add properties directly to the prototype:

Man.prototype.salutation = "Mr.";

Let's make that possible inside of the class body:

class Man extends Person {
  salutation = "Mr.";
}

This syntax alone would be a vast improvement to existing JavaScript syntax, and would be worthy of inclusion without additional improvements.

That said, let's take the opportunity to make two additional improvements while we're at it.

Let's Fix a Common Bug

A common problem with defining properties on a prototype comes when you define a property to be an object, like an Array:

Man.prototype.children = [];

Let's say that instead of evaluating the right hand side of an assignment immediately, and sharing it across all instances, it is evaluated for each new instance:

class Man extends Person {
  children = [];
}

new Man().children === new Man().children // false

When creating a new instance, in addition to invoking the class' constructor, we evaluate the right hand side of each declared property and assign it as a property of the new object.

Extensibility

Existing JavaScript libraries that implement classes perform various actions during the process of creating a new class.

Let's allow classes to define a hook that should be called after they are extended.

Person.extended = function(child) {
  // child is the subclass of Person
  // child.prototype would exist at this point
}

This will allow additional class semantics to be defined by libraries and toolkits.

That's it

Let's try adding a very simple class syntax to JavaScript and see where that takes us.

+1
...really like the idea of function declarations being used to assign class properties. Would it be possible to set private members inside the class (with getters and setters, obv)? Something like:

class Person {
  var age = 9001;

  getAge() {
    reutrn age;
  }
}

"Let's Fix a Common Bug" +1

Hmmm, what's the purpose of this gist?! I don't agree to push pythonic or javaonic syntax to javascript. It's good the way it is now... Furthermore, a language that keeps changing isn't good thing IMHO. What's wrong with the MooTools or Prototype approach to mimic standard classes?!

nagaozen but that would mean people have to actually learn javascript!! oh noesss

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.