Skip to content

Instantly share code, notes, and snippets.

@hugs
Last active December 24, 2016 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hugs/118e62b76f58299923464c632f8a71e3 to your computer and use it in GitHub Desktop.
Save hugs/118e62b76f58299923464c632f8a71e3 to your computer and use it in GitHub Desktop.
Experiments creating new objects in JavaScript, with regular functions and generator functions

Creating New Objects with Generators

Here are some experiments creating new objects in JavaScript... with regular functions and generator functions.

Why?

I've been playing around converting regular functions into generator functions, and I recently ran into a problem: generators are not "new-able". You can't create new objects when the constructor is a generator.

Some background: "Generator expressions cannot be used as constructors." http://stackoverflow.com/questions/32039390/why-are-generator-methods-constructors https://github.com/tc39/tc39-notes/blob/master/es7/2015-07/july-29.md#revisit-67-new--generatorfunction tc39/ecma262#171 https://github.com/anba/test262/commit/bd8c91e250690567240e3aa4ade9a740b94b1aee

So I needed a workaround: How do I create a new object and call the constructor when the constructor (and all its methods) are generators?

Well, with JavaScript, where there's a will, there's a way to implement Atwood's Law any way you want to.

During my research, I found these answers on Stack Overflow was incredibly helpful: http://stackoverflow.com/a/21763808 http://stackoverflow.com/a/29037611


The problem: generators can't be constructors

(Tested with Node v6.9.1)

function* Person(name) {
  this.name = name;
}
Person.prototype.getName = function* () {
  console.log(this.name);
}
var p = new Person("Emmet");


Usage:
------
> var p = new Person("Emmet");
TypeError: Person is not a constructor

Now, let's start experimenting with solutions, starting with a simple standard object

Create a new object, the 'standard' way

function Person(name) {
  this.name = name;
}
Person.prototype.getName = function() {
  console.log(this.name);
}
var p = new Person("Emmet");


Usage:
------
> p.getName()
Emmet
> p
Person { name: 'Emmet' }
> 

Create a new object, without using the 'new' keyword, method #1

function Person(name) { 
  this.name = name;
}
my_person_prototype = {
  getName: function() {
    console.log(this.name);
  }
};
var p = {};
for(var key in my_person_prototype) {
  p[key] = my_person_prototype[key];
}
Person.apply(p, ["Emmet"]);


Usage:
------
> p.getName()
Emmet
> p
{ getName: [Function: getName], name: 'Emmet' }
> 

Create a new object, without using the 'new' keyword, method #2

function Person(name) {
  this.name = name;
}
my_person_prototype = {
  getName: function() {
    console.log(this.name);
  }
};
var p = Object.create(my_person_prototype);
Person.apply(p, ["Emmet"]);


Usage:
------
> p.getName()
Emmet
> p
{ name: 'Emmet' }
> 

Create a new object, without using the 'new' keyword, method #1

now with generator methods...

function Person(name) {
  this.name = name;
}
my_person_prototype = {
  getName: function* () {
    console.log(this.name);
  }
};
var p = {};
for(var key in my_person_prototype){
  p[key] = my_person_prototype[key];
}
Person.apply(p, ["Emmet"]);


Usage:
------
> p.getName().next()
Emmet
{ value: undefined, done: true }
> p
{ getName: [Function: getName], name: 'Emmet' }
> 

Create a new object, without using the 'new' keyword, method #2

now with generator methods...

function Person(name){
  this.name = name;
}
my_person_prototype = {
  getName: function* () {
    console.log(this.name);
  }
};
var p = Object.create(my_person_prototype);
Person.apply(p, ["Emmet"]);


Usage:
------
> p.getName().next()
Emmet
{ value: undefined, done: true }
> p
{ name: 'Emmet' }
> 

Create a new object, without using the 'new' keyword, method #2

with a generator constructor and generator methods...

function* Person(name){
  this.name = name;
}
my_person_prototype = {
  getName: function* () {
    console.log(this.name);
  }
};
var p = Object.create(my_person_prototype);
Person.apply(p, ["Emmet"]).next()


Usage:
------
> p.getName().next()
Emmet
{ value: undefined, done: true }
> p
{ name: 'Emmet' }
> 

Create a new object, without using the 'new' keyword, method #2

with a generator constructor and generator methods... (cleaned up a little bit)

function* Person(name){
  this.name = name;
}

Person.prototype.getName = function* () {
  console.log(this.name);
}

var p = Object.create(Person.prototype);
Person.apply(p, ["Emmet"]).next()

Usage:
------
> p.getName().next()
Emmet
{ value: undefined, done: true }
> p
{ name: 'Emmet' }
> 

// Victory! \o/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment