Create objects

var obj  = {} // curly braces
var nextObj = Object.create(Object.prototype) // object.create
var lastObj = new Object() // new keyword

Assign keys and Values

var obj = {}

obj.param1 = 'new value' // dot notation
obj['param2'] = '2nd new value' // square bracket notation

console.log(obj.param, obj['param2'])

Other stuff

var task = {
  title: 'My title',
  description: 'My description'
}

// objects do internally
Object.defineProperty(task, 'toString', {
  value: function () {
  	return this.title + ' ' + this.description
	},
  writable: false, // allows re-assign a value or not
  enumerable: false, // allows show keys & values or not
  configurable: false // allows change this config or not
})

// trying to change value content
// task.toString = 'hi'

// trying to config settings of the object
// Object.defineProperty(task, 'toString', { enumerable: true })

// enumerating all values
console.log(task)
console.log(Object.entries(task))

// creating an object by inheritance
var urgenTask = Object.create(task)

// but config is already settled and we can't config it, if configurable is false
/* Object.defineProperty(task, 'toString', {
  value() {
    return this.title + ' is urgent'
  },
  writable: false,
  enumerable: false,
  configurable: false
})
console.log(urgenTask.toString())*/

Closures & Alcance

const x = 'lala' // alcance global, acceso en cualquier lado
console.log(x, y, z) // 'lala', undefined, undefined

const f = () => {
	const y = 'lele' // alcance de funcion
	console.log(x, y, z) // 'lala', 'lele', undefined

	return () => {
		const z = 'lolo'
		console.log(x, y, z) // 'lala', 'lele', 'lolo'
	}
}
const f = (x) => {
  return () => {
    console.log(x)
  }
}

// 'adrian se guarda en la memoria de la funcion'
const i = f('adrian')
i()
i()
i()
const auditProps = {
  createdAt: { default: new Date() },
  updatedAt: { default: new Date() },
  createdBy: { type: Schema.Types.ObjectId, ref: 'User' },
  updatedBy: { type: Schema.Types.ObjectId, ref: 'User' },
}

const Model = (defaultProps) => {
  return (name, props) => {
    const schema = moongose.schema({
      ...defaultProps,
      ...props,
    })
    return mongoose.model(name, schema)
  }
}

export const withAudit = Model(auditProps)

// ... en otro archivo
// aqui, esta funcion ya contiene todos los auditProps, y con esto le adicionamos mas props, pasando a ejecutar la creacion de un modelo de mongoose y retornando la respuesta
withAudit('Product', {
  name: string,
  desc: string,
})

Programacion Tactica o point free o middlewares

const f = (ruta, cb) => {
	// ... mucho texto
	const result = computacionPesada()
	cb(resultado)
}

const manejaResultado = (resultado) => {
}

f('/user', manejaResultado)

Currying

// funcion normal con dos agrumentos, que por alguna razon, solo quieres mandarle 1 parametro en lugar de dos
const suma = (a, b) => a + b
suma(2, 3)

/* la manera de aplicar currying
Como se ve, la primera ejecucion solo establece el valor de a y returna una funcion
La segunda ejecucion establece el valor de b y retorna el resultado de a + b

a es guardada en el closure de la primera ejecucion
*/ 
const suma = a => b => a + b  // currying
suma(1)(5)

// el equivalente serĂ­a
const suma = (a) => { // en este ambito se guarda a
	 return (b) => a + b // en este ambito se usa a y b
}

// tambien se puede ejecutar de esta manera
const unoMas = suma(1)
unoMas(5) // 6