Skip to content
tebe edited this page Mar 24, 2022 · 13 revisions

On this page we want to collect common patterns where you normally use non-rethink.js-stuff like prototype.

constructors

Let's start with the old way of doing JS.

// standard js

function User(name) {
  this.name = name;
}

User.prototype.greet = function(greeting) {
  console.log(this.name + ' says "' + (greeting || 'hi!') + '"')
}

var john = new User('John');
john.greet('howdy!'); // logs 'John says "howdy!"' to console

So how can we do this without prototype and new.

// rethink.js

function User(name) {
  var user = {
    name: name
  }
  user.greet = function(greeting) {
    console.log(user.name + ' says "' + (greeting || 'hi!') + '"')
  }
  return user;
}

var john = User('John');
john.greet('howdy!'); // logs 'John says "howdy!"' to console

Pretty straight forward, right? You can hand over the user.greet-method as is as a callback, no binding needed. Downside of this is that's it's slower than the upper version. This only kicks in, if you have a lot of items to construct. However, if you're forced to bind the this-pointer performance of prototype-based js becomes slower. In rethink.js you never need to bind a this-pointer.

We are currently working on a more meaningful performance test. We think the performance loss is not as high in real world use cases since using the constructed instances takes greater space than constructing them.

inheritance

Again, here is the standard way of doing JS.

// standard js

function User(name) {
  this.name = name;
}

User.prototype.greet = function(greeting) {
  console.log(this.name + ' says "' + (greeting || 'hi!') + '"')
}

function Pirate(name) {
  User.call(this, name);
}
Pirate.prototype = Object.create(User.prototype)

Pirate.prototype.greet = function() {
  return User.greet.call(this, 'Aye!')  
}

var john = new Pirate('John');
john.greet(); // logs 'John says "aye!"' to console

And now the version without prototype and new.

// rethink.js

function User(name) {
  var user = {
    name: name
  }
  user.greet = function(greeting) {
    console.log(user.name + ' says "' + (greeting || 'hi!') + '"')
  }
  return user;
}

function Pirate(name) {
  var pirate = User(name);
  var superGreet = pirate.greet;
  pirate.greet = function() {
    superGreet('Aye!');
  };
  return pirate;
}

var john = Pirate('John');
john.greet(); // logs 'John says "Aye!"' to console

The readability has much improved here. The performance is also worse here but only matters when you create a lot (>1000) of items. Also when you use bind rethink is again faster.

mixins

Mixins are a common way to encapsulate functionality. With rethink.js mixins are pretty easy to achieve:

function Saveable(thing) {
  thing.save = function() {
    // code to save the thing
  };
}

function User(name) {
  var user = {
    name: name
  };
  Saveable(user);
}

var john = User('John');
john.save(); // saves john

type-checking

In standard javascript you can use instanceof to check, what kind of object you deal with. Since we don't use prototypes here, we can't rely on instanceof here. There a few possibilities to allow the type checking.

The simplest is to annotate a type property on every object.

function User(name) {
  var user = {
    type: 'user',
    name: name
  };
}

var john = User('John');
john.type === 'user'; // true
john.type === 'tree'; // false

An other way would be to set a boolean property to the object:

function User(name) {
  var user = {
    isUser: true,
    name: name
  };
}

var john = User('John');
john.isUser; // true
john.isTree; // undefined and therefore falsey
Clone this wiki locally