Skip to content

Instantly share code, notes, and snippets.

@myfonj
Created November 21, 2020 16:33
Show Gist options
  • Save myfonj/9bda95fe3b2c08cc76da3306dbde9816 to your computer and use it in GitHub Desktop.
Save myfonj/9bda95fe3b2c08cc76da3306dbde9816 to your computer and use it in GitHub Desktop.
POC of JavaScript Object class with property order control via setBefore(pivot, key, value) and setFirst(key, value)
class FOJO {
constructor(o) {
this.object = Object.assign({}, o)
this.entries = Object.entries(this.object)
return new Proxy(this, this)
}
ownKeys() {
return Object.keys(this.object)
}
get(target, key) {
switch (key) {
case 'setFirst': return (key, value) => {
this.entries.unshift([key, value])
this.object = Object.fromEntries(this.entries)
}
case 'setBefore': return (pivotKey, key, value) => {
if ((pivotKey in this.object) == false) {
throw "No."
}
let i = this.entries.findIndex(a => a[0] === pivotKey)
this.entries.splice(i, 0, [key, value])
this.object = Object.fromEntries(this.entries)
}
default: return this.object[key]
}
}
set(target, key, value) {
if ((key in this.object) == false) {
this.object[key] = value
this.entries.push([key, value])
return value
}
this.object[key] = value
this.entries = Object.entries(this.object)
return value
}
getOwnPropertyDescriptor(target, key, value) {
return Object.getOwnPropertyDescriptor(this.object, key)
}
}
var x = new FOJO({ two: 'second' })
x.four = 'fourth'
x.setBefore('four', 'three', 'third')
x.setFirst('one', 'first')
x.five = 'fifth'
JSON.stringify(x, null, '\t')
// <script>
// POC of Object class with property order control via setBefore(pivot, key, value) and setFirst(key, value)
// proxied "just enough to have getters, setters and JSON.stringify working"
// @see https://twitter.com/LeaVerou/status/1329793951973470214
// @see https://twitter.com/myfonj/status/1329871558349901824
// @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy
console.clear()
class FOJO {
constructor(o) {
console.log('constructor', arguments, this)
this.object = Object.assign({}, o)
this.entries = Object.entries(this.object)
return new Proxy(this, this)
}
ownKeys() {
// A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
console.log('ownKeys', arguments, this)
return Object.keys(this.object)
}
get(target, key) {
// A trap for getting property values.
console.log('get', arguments, this)
switch (key) {
case 'setFirst': return (key, value) => {
this.entries.unshift([key, value])
this.object = Object.fromEntries(this.entries)
}
case 'setBefore': return (pivotKey, key, value) => {
if ((pivotKey in this.object) == false) {
throw "No."
}
let i = this.entries.findIndex(a => a[0] === pivotKey)
this.entries.splice(i, 0, [key, value])
this.object = Object.fromEntries(this.entries)
}
default: return this.object[key]
}
}
set(target, key, value) {
// A trap for setting property values.
console.log('set', arguments, this)
if ((key in this.object) == false) {
this.object[key] = value
this.entries.push([key, value])
return value
}
this.object[key] = value
this.entries = Object.entries(this.object)
return value
}
apply(target, key, value) {
// A trap for a function call.
console.log('apply', arguments, this)
}
construct(target, key, value) {
// A trap for the new operator.
console.log('construct', arguments, this)
}
defineProperty(target, key, value) {
// A trap for Object.defineProperty.
console.log('defineProperty', arguments, this)
}
deleteProperty(target, key, value) {
// A trap for the delete operator.
console.log('deleteProperty', arguments, this)
}
getOwnPropertyDescriptor(target, key, value) {
// A trap for Object.getOwnPropertyDescriptor.
console.log('getOwnPropertyDescriptor', arguments, this)
return Object.getOwnPropertyDescriptor(this.object, key)
}
getPrototypeOf(target, key, value) {
// A trap for Object.getPrototypeOf.
console.log('getPrototypeOf', arguments, this)
}
has(target, key, value) {
// A trap for the in operator.
console.log('has', arguments, this)
}
isExtensible(target, key, value) {
// A trap for Object.isExtensible.
console.log('isExtensible', arguments, this)
}
preventExtensions(target, key, value) {
// A trap for Object.preventExtensions.
console.log('preventExtensions', arguments, this)
}
setPrototypeOf(target, key, value) {
// A trap for Object.setPrototypeOf.
console.log('setPrototypeOf', arguments, this)
}
}
var x = new FOJO({ two: 2 })
x.four = 4
x.setBefore('four', 'three', 3)
x.setFirst('one', 1)
x.five = 5
console.log(JSON.stringify(x))
// == '{"one":1,"two":2,"three":3,"four":4,"five":5}'
// </script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment