Skip to content

pOxaes/JSOO

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 

Repository files navigation

OOP in JS

What

3 ways for a function to return an Object:

  • Constructor functions
  • ES6 Class (made up constructor)
  • Factory

common

  • methods stored in a shared prototype
  • private data via closures

examples

constructor

function Drums () {}

Drums.prototype.play = function () {
  console.log('BOUM');
}

const drumInstance = new Drums();
drumInstance.play(); // BOUM

class

class Drums {
  play () {
    console.log('BOUM');
  }
}

const drumInstance = new Drums();
drumInstance.play(); // BOUM

Under the hood, still a constructor:

typeof class DoubleRainbow {} // function

Babel

var Drums = function () {
  function Drums() {
    _classCallCheck(this, Drums);
  }

  // Attach play method to Drums prototype
  _createClass(Drums, [{
    key: 'play',
    value: function play() {
      console.log('BOUM');
    }
  }]);

  return Drums;
}();

var drumInstance = new Drums();

factory

objects with its own properties: custom part of objects

  • more flexible
  • can create objects with initial data
function createDrum() {
  return {
    play() {
      console.log('BOUM');
    }
  }
}
const drumInstance = createDrum();
drumInstance.play(); // BOUM

// play is a drumInstance's property
console.log(drumInstance) // { play: ƒ }

objects with assigned prototype: common part of objects

  • costs less space & memory (it doesn't create properties)

Mozilla, Object.create

The Object.create() method creates a new object with the specified prototype object and properties.

function createDrum() {
  const prototypeLike = {
    play () {
      console.log('BOUM');
    }
  };
  return Object.create(prototypeLike);
}

const drumInstance = createDrum();
drumInstance.play(); // BOUM

// play is a drumInstance.prototype's property
console.log(drumInstance) // {}

Private properties

  • Closures, closures and closures

Examples with...

...class...

class Drums {
  constructor() {
    const sound = 'BOUM'; // private workaround
    this.getSound = () => sound;
  }

  play () {
    console.log(this.getSound());
  }
}

const drumInstance = new Drums();
drumInstance.play(); // BOUM

using Symbol

const _name = Symbol('name');

class Test {
  constructor(name) {
    this[_name] = name;
  }

  get name() { return this[_name]; }
}

...factory...

function createDrum() {
  const sound = 'BOUM'; // private variable

  return {
    play () {
      console.log(sound);
    }
  };
}

const drumInstance = createDrum();
drumInstance.play(); // BOUM

Inheritance

Class and constructor

Prototype is a chain, populated with each extension

  • protoA inherit from protoB
  • protoB inherit from protoC
  • ...
  • protoZ inherit from Object's prototype

Reminder: When you try to access a property on an object, it checks the object’s own properties first. If it doesn’t find it there, it checks the prototype.

with a class

class A {}

class B extends A {}

with a constructor

function Parent() {}

function Child() {}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

Factory

objects with assigned prototype

function createDrum() {
  return Object.create({
    whoAreYou() {
      console.log('A Drum!');
    },
    play () {
      console.log('BOUM');
    }
  })
}

function createSmallDrum() {
  return Object.create(Object.assign(createDrum.call(this), {
    play() {
      console.log('little boum')
    }
  }));
}

const smallDrumInstance = createSmallDrum();
smallDrumInstance.play(); // little boum
smallDrumInstance.whoAreYou(); // A Drum!

Note: if you want to use Object spread, createSmallDrum becomes:

const drum = createDrum.call(this);
return Object.create({
  ...drum.__proto__,
  play() {
    console.log('little boum')
  }
});

__proto__ property of an object is a pointer to the object's constructor function's prototype property

foo.__proto__ === foo.constructor.prototype

objects with custom properties

function createDrum() {
  return {
    sound: 'BOUM',
    whoAreYou() {
      console.log('A Drum!');
    },
    play() {
      console.log(this.sound);
    }
  }
}

function createSmallDrum() {
  return Object.assign(createDrum.call(this), {
    sound: 'little boum'
  });
}

const smallDrumInstance = createSmallDrum();
smallDrumInstance.play(); // little boum
smallDrumInstance.whoAreYou(); // A Drum!

Note that you should not use arrow function in the returned Object because the context will be the function and not the object itself.

More...

  • return an object of any subtype of their return type: the object to be returned could be of several different types depending on some parameter
  • mix custom properties + prototype
  • compose multiple objects: more flexible
const createHuman() {
  return {
    canWalk: true,
    canTalk: true,
    canSee: false,
    canSleepWithoutPeeing: true
  }
}

const createBaby() {
  return {
    canSleepWithoutPeeing: false
  }
}

const createAlien() {
  return {
    canFly: true,
    canTalk: false
  }
}

const createSuperMixedEntity() {
  return Object.assign(createHuman(), createBaby(), createAlien())
}

Benchmark

https://jsperf.com/prototype-vs-factory-vs-class

  • Factory: 1 093 Ops / sec
  • Prototype: 4 370 Ops / sec
  • Class: 4 414 Ops / sec

Factory 75% slower

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors