Eirik Langholm Vullum PRO
JavaScript fanatic that loves node.js and React.
// macro (sweet.js)
syntax hi = function (ctx) {
return #`console.log('hello, world!')`;
};
// macro (sweet.js)
syntax hi = function (ctx) {
return #`console.log('hello, world!')`;
};
// before compile/expansion
hi
// macro (sweet.js)
syntax hi = function (ctx) {
return #`console.log('hello, world!')`;
};
// before compile/expansion
hi
// after compile/expansion
console.log('hello, world!');
// macro (sweet.js)
operator >>= left 1 = (left, right) => {
return #`${left}.then(${right})`;
};
// macro (sweet.js)
operator >>= left 1 = (left, right) => {
return #`${left}.then(${right})`;
};
// before compile/expansion
fetch('/foo.json') >>= resp => { return resp.json() }
>>= json => { return processJson(json) }
// macro (sweet.js)
operator >>= left 1 = (left, right) => {
return #`${left}.then(${right})`;
};
// before compile/expansion
fetch('/foo.json') >>= resp => { return resp.json() }
>>= json => { return processJson(json) }
// after compile/expansion
fetch("/foo.json").then(resp => {
return resp.json();
}).then(json => {
return processJson(json);
});
(before the code runs)
const hero = {
health: 100,
backpack: ['carrots', 'beer'],
weapon: 'sword'
};
const hero = {
health: 100,
backpack: ['carrots', 'beer'],
weapon: 'sword'
};
const keys = Object.keys(hero);
const hero = {
health: 100,
backpack: ['carrots', 'beer'],
weapon: 'sword'
};
const keys = Object.keys(hero);
console.log(keys);
// ['health', 'backpack', 'weapon']
function grumpySum(a, b) {
if (a > 5) {
grumpySum = () => 0;
}
return a + b;
}
function grumpySum(a, b) {
return a + b;
}
function grumpySum(a, b) {
if (a > 5) {
grumpySum = () => 0;
}
return a + b;
}
console.log(grumpySum(1, 1)) // -> 2
console.log(grumpySum(10, 1)) // -> 11
function grumpySum(a, b) {
if (a > 5) {
grumpySum = () => 0;
}
return a + b;
}
console.log(grumpySum(1, 1)) // -> 2
console.log(grumpySum(10, 1)) // -> 11
console.log(grumpySum(2, 3)) // -> 0
function grumpySum(a, b) {
if (a > 5) {
grumpySum = () => 0;
}
return a + b;
}
console.log(grumpySum(1, 1)) // -> 2
console.log(grumpySum(10, 1)) // -> 11
console.log(grumpySum(2, 3)) // -> 0
console.log(grumpySum(2, 100)) // -> 0
function grumpySum(a, b) {
if (a > 5) {
grumpySum = () => 0;
}
return a + b;
}
console.log(grumpySum(1, 1)) // -> 2
var hero = {
health: 100,
};
Very limited / not very flexible
var hero = {
health: 100,
};
Object.defineProperty(hero, 'status', {
get: function() {
},
});
var hero = {
health: 100,
};
Object.defineProperty(hero, 'status', {
get: function() {
if (this.health > 50) {
return 'fit like a champ'
}
},
});
var hero = {
health: 100,
};
Object.defineProperty(hero, 'status', {
get: function() {
if (this.health > 50) {
return 'fit like a champ'
} else {
return 'badly hurt';
}
},
});
var hero = {
health: 100,
};
Object.defineProperty(hero, 'status', {
get: function() {
if (this.health > 50) {
return 'fit like a champ'
} else {
return 'badly hurt';
}
},
});
hero.status // -> fit like a champ
(while the code runs)
(is this useful)
new Proxy(target, handler)
const proxy = new Proxy(target, handler);
{}
{}
[]
{}
[]
function() {}
{}
[]
function() {}
new Proxy(...)
{}
[]
function() {}
new Proxy(...)
// any type of object
const proxy = new Proxy({}, {})
const proxy = new Proxy({}, {})
typeof proxy === 'object'
var handler = {
};
var handler = {
get: function(target, name) {
return 37;
}
};
var handler = {
get: function(target, name) {
return 37;
}
};
var p = new Proxy({}, handler);
var handler = {
get: function(target, name) {
return 37;
}
};
var p = new Proxy({}, handler);
console.log(p.a); // 37
var handler = {
get: function(target, name) {
return 37;
}
};
var p = new Proxy({}, handler);
console.log(p.a); // 37
console.log(p.b); // 37
proxy = new Proxy({}, {
get: ...,
set: ...,
has: ...,
apply: ...,
construct: ...,
defineProperty: ...,
getOwnPropertyDescriptor: ...,
deleteProperty: ...,
getPrototypeOf: ...,
setPrototypeOf: ...,
isExtensible: ...,
preventExtensions: ...,
ownKeys: ...,
});
const hero = { health: 100 };
const hero = { health: 100 };
Reflect.get(hero, 'health'); // 100
proxy = new Proxy({}, {
get: ...,
set: ...,
has: ...,
apply: ...,
construct: ...,
defineProperty: ...,
getOwnPropertyDescriptor: ...,
deleteProperty: ...,
getPrototypeOf: ...,
setPrototypeOf: ...,
isExtensible: ...,
preventExtensions: ...,
ownKeys: ...,
});
proxy = new Proxy({}, {
get: Reflect.get,
set: Reflect.set,
has: Reflect.has,
apply: Reflect.apply,
construct: Reflect.construct,
defineProperty: Reflect.defineProperty,
getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor,
deleteProperty: Reflect.deleteProperty,
getPrototypeOf: Reflect.getPrototypeOf,
setPrototypeOf: Reflect.setPrototypeOf,
isExtensible: Reflect.isExtensible,
preventExtensions: Reflect.preventExtensions,
ownKeys: Reflect.ownKeys,
});
function logAccessToProperties(obj) {
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
});
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
get(target, key) {
},
});
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key);
},
});
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key);
return Reflect.get(target, key);
},
});
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key);
return Reflect.get(target, key);
},
set(target, key, value) {
}
});
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key);
return Reflect.get(target, key);
},
set(target, key, value) {
console.log('Updated key', key, 'to', value);
}
});
}
function logAccessToProperties(obj) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key);
return Reflect.get(target, key);
},
set(target, key, value) {
console.log('Updated key', key, 'to', value);
Reflect.set(target, key, value);
}
});
}
const person = {
name: 'Eirik',
age: 30,
};
const person = {
name: 'Eirik',
age: 30,
};
const personWithAccessLogging =
logAccessToProperties(person);
const person = {
name: 'Eirik',
age: 30,
};
const personWithAccessLogging =
logAccessToProperties(person);
personWithAccessLogging.age;
const person = {
name: 'Eirik',
age: 30,
};
const personWithAccessLogging =
logAccessToProperties(person);
personWithAccessLogging.age;
// Accessed age
const person = {
name: 'Eirik',
age: 30,
};
const personWithAccessLogging =
logAccessToProperties(person);
personWithAccessLogging.age;
// Accessed age
personWithAccessLogging.age = 31;
const person = {
name: 'Eirik',
age: 30,
};
const personWithAccessLogging =
logAccessToProperties(person);
personWithAccessLogging.age;
// Accessed age
personWithAccessLogging.age = 31;
// Updated key age to 31
function observable(obj, onChange) {
}
function observable(obj, onChange) {
return new Proxy(obj, {
};
}
function observable(obj, onChange) {
return new Proxy(obj, {
set(target, key, value) {
}
};
}
function observable(obj, onChange) {
return new Proxy(obj, {
set(target, key, value) {
Reflect.set(target, key, value);
}
};
}
function observable(obj, onChange) {
return new Proxy(obj, {
set(target, key, value) {
Reflect.set(target, key, value);
onChange({ key, value });
}
};
}
let person = {
name: 'Eirik',
age: 31,
};
let person = {
name: 'Eirik',
age: 31,
};
person = observable(person, ({ key, value }) => {
console.log(`${key} changed to ${value}`);
});
let person = {
name: 'Eirik',
age: 31,
};
person = observable(person, ({ key, value }) => {
console.log(`${key} changed to ${value}`);
});
person.name = 'Frank';
let person = {
name: 'Eirik',
age: 31,
};
person = observable(person, ({ key, value }) => {
console.log(`${key} changed to ${value}`);
});
person.name = 'Frank';
// name changed to Frank
let person = {
name: 'Eirik',
age: 31,
};
person = observable(person, ({ key, value }) => {
console.log(`${key} changed to ${value}`);
});
person.name = 'Frank';
// name changed to Frank
person.age = 40;
let person = {
name: 'Eirik',
age: 31,
};
person = observable(person, ({ key, value }) => {
console.log(`${key} changed to ${value}`);
});
person.name = 'Frank';
// name changed to Frank
person.age = 40;
// age changed to 40
const stories = [
{
id: 'story-1',
title: 'The Last Question',
author: {
$ref: 'people',
id: 'person-1'
},
liked_by: [
{ $ref: 'people', id: 'person-1' },
{ $ref: 'people', id: 'person-2' }
],
read_by: [
{ $ref: 'people', id: 'person-1' },
{ $ref: 'people', id: 'person-2' }
],
},
{
...
}
];
const people = [
{
id: 'person-1',
name: 'Isaac Asimov',
authored: [
{ $ref: 'stories', id: 'story-1' },
],
read: [
{ $ref: 'stories', id: 'story-1' },
],
liked: [
{ $ref: 'stories', id: 'story-1' },
],
},
{
...
}
];
const stories = [
{
id: 'story-1',
title: 'The Last Question',
author: {
$ref: 'people',
id: 'person-1'
},
liked_by: [
{ $ref: 'people', id: 'person-1' },
{ $ref: 'people', id: 'person-2' }
],
read_by: [
{ $ref: 'people', id: 'person-1' },
{ $ref: 'people', id: 'person-2' }
],
},
{
...
}
];
const people = [
{
id: 'person-1',
name: 'Isaac Asimov',
authored: [
{ $ref: 'stories', id: 'story-1' },
],
read: [
{ $ref: 'stories', id: 'story-1' },
],
liked: [
{ $ref: 'stories', id: 'story-1' },
],
},
{
...
}
];
const stories = [
{
id: 'story-1',
title: 'The Last Question',
author: {
$ref: 'people',
id: 'person-1'
},
liked_by: [
{ $ref: 'people', id: 'person-1' },
{ $ref: 'people', id: 'person-2' }
],
read_by: [
{ $ref: 'people', id: 'person-1' },
{ $ref: 'people', id: 'person-2' }
],
},
{
...
}
];
const people = [
{
id: 'person-1',
name: 'Isaac Asimov',
authored: [
{ $ref: 'stories', id: 'story-1' },
],
read: [
{ $ref: 'stories', id: 'story-1' },
],
liked: [
{ $ref: 'stories', id: 'story-1' },
],
},
{
...
}
];
const graph = {
stories: [...],
people: [...]
}
Plain JSON
const nameOfFirstLiker =
const nameOfFirstLiker =
graph.stories[0].liked_by
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))[0]
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))[0]
.name;
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))[0]
.name;
const titleOfFirstLikedStoryByAuthor =
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))[0]
.name;
const titleOfFirstLikedStoryByAuthor =
graph[graph.stories[0].author.$ref]
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))[0]
.name;
const titleOfFirstLikedStoryByAuthor =
graph[graph.stories[0].author.$ref]
.find((p) => p.id === graph.stories[0].author.id))
const nameOfFirstLiker =
graph.stories[0].liked_by
.map(({ $ref, id }) => graph[$ref].find((p) => p.id === id))[0]
.name;
const titleOfFirstLikedStoryByAuthor =
graph[graph.stories[0].author.$ref]
.find((p) => p.id === graph.stories[0].author.id))
.title;
const nameOfFirstLiker =
graph.stories[0].liked_by[0].name
const nameOfFirstLiker =
graph.stories[0].liked_by[0].name
const titleOfFirstLikedStoryByAuthor =
graph.stories[0].author.likes[0].title
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [
{ id: 'story-1', $ref: 'stories' },
]
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
},
...
}],
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [
{ id: 'story-1', $ref: 'stories' }
]
}
...
}],
}
}
const populatedNode = populate( )
const populatedNode = populate( )
const populatedNode = populate(graph, )
const populatedNode = populate(graph, node)
const populatedNode = populate(graph, node)
const populatedStory = populate(graph, graph.stories[0])
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [
{ id: 'story-1', $ref: 'stories' },
]
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
},
...
}],
}
}
// Boom
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [
{ id: 'story-1', $ref: 'stories' }
]
}
...
}],
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [
{ id: 'story-1', $ref: 'stories' },
]
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
},
...
}],
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: [
{ id: 'story-1', $ref: 'stories' }
]
}
...
}],
}
}
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: [{
id: 'story-1',
$ref: 'stories'
}]
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: [{
id: 'story-1',
$ref: 'stories'
}]
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: [{
id: 'story-1',
$ref: 'stories'
}]
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: [{
id: 'story-1',
$ref: 'stories'
}]
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
id: 'ted-chiang-1',
$ref: 'people'
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: [{
id: 'story-1',
$ref: 'stories'
}]
},
{
...
}
];
const nameOfFirstLiker =
graph.stories[0].liked_by.people[0].name
const titleOfFirstLikedStory =
graph.people[0].author.likes[0].title
github.com/eiriklv/json-populate
TypeError: undefined is not a function
TypeError: Cannot read property 'undefined' of undefined
const Undefined = new Proxy(function() {}, {
});
const Undefined = new Proxy(function() {}, {
get(target, key, receiver) {
},
});
const Undefined = new Proxy(function() {}, {
get(target, key, receiver) {
if (key === 'name') {
return 'Undefined';
}
return Undefined;
},
});
const Undefined = new Proxy(function() {}, {
get(target, key, receiver) {
if (key === 'name') {
return 'Undefined';
}
return Undefined;
},
apply() {
},
});
const Undefined = new Proxy(function() {}, {
get(target, key, receiver) {
if (key === 'name') {
return 'Undefined';
}
return Undefined;
},
apply() {
return Undefined;
},
});
function seatbelt(obj) {
}
function seatbelt(obj) {
return new Proxy(obj, {
});
}
function seatbelt(obj) {
return new Proxy(obj, {
get(target, key) {
}
});
}
function seatbelt(obj) {
return new Proxy(obj, {
get(target, key) {
const accessedProperty = Reflect.get(target, key);
}
});
}
function seatbelt(obj) {
return new Proxy(obj, {
get(target, key) {
const accessedProperty = Reflect.get(target, key);
if (typeof accessedProperty === 'object') {
return seatbelt(accessedProperty);
}
}
});
}
function seatbelt(obj) {
return new Proxy(obj, {
get(target, key) {
const accessedProperty = Reflect.get(target, key);
if (typeof accessedProperty === 'object') {
return seatbelt(accessedProperty);
} else {
return accessedProperty == undefined ?
Undefined :
accessedProperty;
}
}
});
}
const iNeverFail = seatbelt({
});
const iNeverFail = seatbelt({
foo: 'bar',
baz: {
qux: 10,
name: 'yoyo',
},
});
iNeverFail.foo
iNeverFail.foo
// bar
iNeverFail.foo
// bar
iNeverFail.baz.qux
iNeverFail.foo
// bar
iNeverFail.baz.qux
// 10
iNeverFail.foo
// bar
iNeverFail.baz.qux
// 10
iNeverFail.baz.name
iNeverFail.foo
// bar
iNeverFail.baz.qux
// 10
iNeverFail.baz.name
// yoyo
iNeverFail
iNeverFail.notHere
iNeverFail.notHere.notAfunction
iNeverFail.notHere.notAfunction()
iNeverFail.notHere.notAfunction().nope
iNeverFail.notHere.notAfunction().nope
// [Function: Undefined]
iNeverFail.notHere.notAfunction().nope
// [Function: Undefined]
iNeverFail.foo.b.a.g.e.d().sf().d
iNeverFail.notHere.notAfunction().nope
// [Function: Undefined]
iNeverFail.foo.b.a.g.e.d().sf().d
// [Function: Undefined]
Object.setPrototypeOf(
Object.prototype,
seatbelt({})
);
/**
* Nobel prize material
*/
Object.setPrototypeOf(
Object.prototype,
seatbelt({})
);
@eiriklv
By Eirik Langholm Vullum