import {NOTE} from './_util'

// ===========================
// How the `new` keyword works
// ===========================

// This module will implement the JavaScript's `new` keyword as a function,
// that can be invoked on a normal constructor function to faithfully replicate
// the keyword's functionality. The function is by no means useful in real-life
// situations. It's purpose is to reveal the guts of the `new` keyword so you
// can understand what it does.

// For more information on prototypal inhertiance in JavaScript (which covers
// the usage of constructor functions), take a look at the `proto.js` module.

// We will start by defining a constructor function.

function Foo(name) {
  this.name = name
}

// We also want the objcts to inherit some properties, which we will set using
// the constructor's `prototype` property.

Foo.prototype.exclaim = function () {
  console.log(this.name + '!')
}

// Normally, we would use this constructor like so:

NOTE('Create foo using Foo constructor')
let foo = new Foo('Superman')
console.log('foo.name ===', foo.name) // foo.name === Superman
NOTE('foo.exclaim()')
foo.exclaim() // Superman!

// A function that replaces the `new` keyword may look something like this:

const neo = function (ctor, ...ctorArgs) {
  // Create the new object
  let obj = {}
  // Set the object's prototype to constructor's `prototype` property
  Object.setPrototypeOf(obj, ctor.prototype)
  // Apply the constructor to the new object using constructor arguments
  ctor.apply(obj, ctorArgs)
  // Return the new object
  return obj
}

// Let's see if the function actually does what we want.

NOTE('Create bar using Foo constructor and neo() function')
let bar = neo(Foo, 'Batman')
console.log('bar.name === ', bar.name) // bar.name === Batman
NOTE('bar.exclaim()')
bar.exclaim() // Batman!

// Hopefully, the `new` keyword has been demistified and you have a better
// understanding of what exactly it does.

// NOTE: In the example function, the fist and second step can be merged into
// a single `Object.create()` call. This has not been done in order to break
// down the operations that the `new` keyword performs. A slightly shorter
// version of the `neo()` function may look lke this:

const neo2 = function (ctor, ...ctorArgs) {
  let obj = Object.create(ctor.prototype)
  ctor.apply(obj, ctorArgs)
  return obj
}

@@ -507,18 +507,18 @@
 al inher
-t
 i
+t
 ance in 
@@ -741,16 +741,17 @@
  the obj
+e
 cts to i
@@ -1873,17 +1873,17 @@
 been dem
-i
+y
 stified 
@@ -2222,16 +2222,17 @@
 y look l
+i
 ke this:

Fix spelling