Eirik Langholm Vullum PRO
JavaScript fanatic that loves node.js and React.
Create your own..
// 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);
});
(at least 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)
we want to
we strive for
and hiding the dirty details behind abstractions
it's all about providing a
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 name in target ?
target[name] : 37;
}
};
var handler = {
get: function(target, name) {
return name in target ?
target[name] : 37;
}
};
var p = new Proxy({}, handler);
var handler = {
get: function(target, name) {
return name in target ?
target[name] : 37;
}
};
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
var handler = {
get: function(target, name) {
return name in target ?
target[name] : 37;
}
};
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
var handler = {
get: function(target, name) {
return name in target ?
target[name] : 37;
}
};
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 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,
});
const person = {
name: 'Eirik',
age: 31,
};
const person = {
name: 'Eirik',
age: 31,
};
const { proxy, revoke } = Proxy.revocable(person, {
get(target, key) {
return Reflect.get(target, key);
}
});
const person = {
name: 'Eirik',
age: 31,
};
const { proxy, revoke } = Proxy.revocable(person, {
get(target, key) {
return Reflect.get(target, key);
}
});
console.log(proxy.name);
// Eirik
const person = {
name: 'Eirik',
age: 31,
};
const { proxy, revoke } = Proxy.revocable(person, {
get(target, key) {
return Reflect.get(target, key);
}
});
console.log(proxy.name);
// Eirik
revoke();
const person = {
name: 'Eirik',
age: 31,
};
const { proxy, revoke } = Proxy.revocable(person, {
get(target, key) {
return Reflect.get(target, key);
}
});
console.log(proxy.name);
// Eirik
revoke();
console.log(proxy.name);
// TypeError: Cannot perform 'get' on a proxy that has been revoked
function validate(obj, validations) {
}
function validate(obj, validations) {
return new Proxy(obj, {
});
}
function validate(obj, validations) {
return new Proxy(obj, {
set(target, key, value) {
}
});
}
function validate(obj, validations) {
return new Proxy(obj, {
set(target, key, value) {
const validate = validations[key] || (() => true);
}
});
}
function validate(obj, validations) {
return new Proxy(obj, {
set(target, key, value) {
const validate = validations[key] || (() => true);
validate(value);
}
});
}
function validate(obj, validations) {
return new Proxy(obj, {
set(target, key, value) {
const validate = validations[key] || (() => true);
validate(value);
Reflect.set(target, key, value);
return true;
}
});
}
const personValidations = {
}
const personValidations = {
age(value) {
},
name(value) {
}
}
const personValidations = {
age(value) {
if (typeof value !== 'number') {
throw new Error('.age has to be a number!');
}
},
name(value) {
}
}
const personValidations = {
age(value) {
if (typeof value !== 'number') {
throw new Error('.age has to be a number!');
}
},
name(value) {
if (typeof value !== 'string') {
throw new Error('.name has to be a string!');
}
}
}
const person = validate({}, personValidations);
const person = validate({}, personValidations);
person.name = 'Eirik';
person.age = 5;
const person = validate({}, personValidations);
person.name = 'Eirik';
person.age = 5;
person.name = 10;
const person = validate({}, personValidations);
person.name = 'Eirik';
person.age = 5;
person.name = 10;
// Throws -> Error: .name has to be a string!
function logAccessToProperties(obj, ref) {
}
function logAccessToProperties(obj, ref) {
return new Proxy(obj, {
})
}
function logAccessToProperties(obj, ref) {
return new Proxy(obj, {
get(target, key) {
}
})
}
function logAccessToProperties(obj, ref) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key, 'on', ref);
}
})
}
function logAccessToProperties(obj, ref) {
return new Proxy(obj, {
get(target, key) {
console.log('Accessed key', key, 'on', ref);
return Reflect.get(target, key);
}
})
}
const person = {
name: 'Eirik',
age: 31,
};
const person = {
name: 'Eirik',
age: 31,
};
const personWithAccessLogging = logAccessToProperties(person, 'abc');
const person = {
name: 'Eirik',
age: 31,
};
const personWithAccessLogging = logAccessToProperties(person, 'abc');
personWithAccessLogging.age;
// Accessed age on abc
const person = {
name: 'Eirik',
age: 31,
};
const personWithAccessLogging = logAccessToProperties(person, 'abc');
personWithAccessLogging.age;
// Accessed age on abc
personWithAccessLogging.name;
// Accessed name on abc
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 });
},
});
}
function observable(obj, onChange) {
return new Proxy(obj, {
set(target, key, value) {
Reflect.set(target, key, value);
onChange({ key, value });
},
delete(target, key) {
Reflect.delete(target, key);
onChange({ key, value: undefined })
},
});
}
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
function urlBuilder(domain) {
let parts = [];
const proxy = new Proxy(() => {
const returnValue = domain + '/' + parts.join('/');
parts = [];
return returnValue;
}, {
has() {
return true;
},
get(target, key) {
parts.push(key);
return proxy;
},
});
return proxy;
}
Source: https://www.keithcirkel.co.uk/metaprogramming-in-es6-part-3-proxies/
const google = urlBuilder('http://google.com');
const google = urlBuilder('http://google.com');
const url = google
const google = urlBuilder('http://google.com');
const url = google.search
const google = urlBuilder('http://google.com');
const url = google.search.products
const google = urlBuilder('http://google.com');
const url = google.search.products.bacon
const google = urlBuilder('http://google.com');
const url = google.search.products.bacon.and
const google = urlBuilder('http://google.com');
const url = google.search.products.bacon.and.eggs
const google = urlBuilder('http://google.com');
const url = google.search.products.bacon.and.eggs()
const google = urlBuilder('http://google.com');
const url = google.search.products.bacon.and.eggs();
console.log(url);
// http://google.com/search/products/bacon/and/eggs
const stories = [
{
id: 'story-1',
name: 'Blabla',
author: {
person: 'person-1',
},
liked_by: {
people: ['person-1', 'person-2'],
},
read_by: {
people: ['person-1', 'person-2']
},
},
{
...
}
];
const people = [
{
id: 'person-1',
name: 'Per',
authored: {
stories: ['story-1'],
},
read: {
stories: ['story-1'],
},
liked: {
stories: ['story-1'],
},
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Blabla',
author: {
person: 'person-1',
},
liked_by: {
people: ['person-1', 'person-2'],
},
read_by: {
people: ['person-1', 'person-2']
},
},
{
...
}
];
const people = [
{
id: 'person-1',
name: 'Per',
authored: {
stories: ['story-1'],
},
read: {
stories: ['story-1'],
},
liked: {
stories: ['story-1'],
},
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Blabla',
author: {
person: 'person-1',
},
liked_by: {
people: ['person-1', 'person-2'],
},
read_by: {
people: ['person-1', 'person-2']
},
},
{
...
}
];
const people = [
{
id: 'person-1',
name: 'Per',
authored: {
stories: ['story-1'],
},
read: {
stories: ['story-1'],
},
liked: {
stories: ['story-1'],
},
},
{
...
}
];
const graph = {
stories: [...],
people: [...]
}
Plain JSON
const nameOfFirstLiker =
graph.stories[0].liked_by.people[0].name
const nameOfFirstLiker =
graph.stories[0].liked_by.people[0].name
const nameOfFirstLike =
graph.people[0].author.person.likes[0].name
const nameOfFirstLiker = graph.stories[0].liked_by.people
const nameOfFirstLiker = graph.stories[0].liked_by.people
.map(({ id }) => graph.people.find((p) => p.id === id))
const nameOfFirstLiker = graph.stories[0].liked_by.people
.map(({ id }) => graph.people.find((p) => p.id === id))
.find((person, index) => index === 0)
const nameOfFirstLiker = graph.stories[0].liked_by.people
.map(({ id }) => graph.people.find((p) => p.id === id))
.find((person, index) => index === 0)
.name;
const nameOfFirstLiker = graph.stories[0].liked_by.people
.map(({ id }) => graph.people.find((p) => p.id === id))
.find((person, index) => index === 0)
.name;
const nameOfFirstLike = graph.people[0].author.person.likes.stories
.map(({ id }) => graph.stories.find((s) => s.id === id))
.find((story, index) => index === 0)
.name;
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
{
id: 'person-1',
name: 'Per',
authored: {
stories: ['story-1'],
},
read: {
stories: ['story-1'],
}
}
{
id: 'person-1',
name: 'Per',
authored: {
stories: ['story-1'],
},
read: {
stories: ['story-1'],
},
liked: {
stories: ['story-1'],
}
}
{
id: 'person-1',
name: 'Per',
authored: {
stories: ['story-1'],
},
lists: [{
name: 'Summer reading',
stories: [
'story-1',
'story-2',
'story-3',
]
}]
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1'
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: {
stories: ['story-1'],
}
}
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: {
stories: [{
id: 'story-1',
name: 'Story of Your Life',
...
}],
}
}
}
}
function populateByAssign(depth = 0, collections = {}, object) {
if (!object) { return object;}
const collectionKeys = Object.keys(collections);
function populateRecursively(depthLeft, subItem) {
if (!subItem) {
return subItem;
}
const objectKeys = Object.keys(subItem);
return objectKeys.reduce((result, key) => {
if (
collectionKeys.includes(key) &&
Array.isArray(subItem[key])
) {
return {
...result,
[key]: !depthLeft ? (
subItem[key]
) : (
subItem[key]
.map(getByIdFromCollection(collections[key]))
.map((item) => populateRecursively(depthLeft - 1, item))
)
};
} else if (
collectionKeys.includes(key) &&
subItem[key] &&
typeof subItem[key] === 'object'
) {
return {
...result,
[key]: !depthLeft ? (
subItem[key]
) : (
Object.keys(subItem[key]).reduce((result, id) => {
return {
...result,
[id]: populateRecursively(depthLeft - 1, getByIdFromCollection(collections[key])(id))
}
}, { ...subItem[key] })
)
};
} else if (collectionKeys.includes(plural(key))) {
return {
...result,
[key]: !depthLeft ? (
subItem[key]
) : (
populateRecursively(depthLeft - 1, getByIdFromCollection(collections[plural(key)])(subItem[key]))
)
};
} else if (Array.isArray(subItem[key])) {
return {
...result,
[key]: !depthLeft ? (
subItem[key]
) : (
subItem[key]
.map((item) => populateRecursively(depthLeft, item))
)
};
} else if (subItem[key] && typeof subItem[key] === 'object') {
return {
...result,
[key]: !depthLeft ? (
subItem[key]
) : (
populateRecursively(depthLeft, subItem[key])
)
}
} else {
return result;
}
}, { ...subItem });
}
return Array.isArray(object) ? (
object.map((item) => populateRecursively(depth, item))
) : (
populateRecursively(depth, object)
);
}
const populatedNode = populate( )
const populatedNode = populate(depth, )
const populatedNode = populate(depth, graph, )
const populatedNode = populate(depth, graph, obj)
const populatedNode = populate(depth, graph, obj)
const populatedPerson = populate(3, graph, graph.people[0])
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1'
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: {
stories: ['story-1'],
}
}
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: {
stories: [{
id: 'story-1',
name: 'Story of Your Life',
...
}],
}
}
}
}
// Boom
function populateByProxy(depth = 0, collections = {}, object) {
if (!object || typeof object !== 'object') {
return object;
}
const collectionKeys = Reflect.ownKeys(collections);
const handler = {
get(target, key, receiver) {
const value = Reflect.get(target, key, receiver);
if (typeof key === 'symbol' || depth <= 0) {
return value;
}
if (Array.isArray(value) && collectionKeys.includes(key)) {
return value
.map(getByIdFromCollection(collections[key]))
.map(populateByProxy.bind(null, depth - 1, collections));
}
if (typeof value === 'object' && collectionKeys.includes(key)) {
return Reflect.ownKeys(value)
.map(getByIdFromCollection(collections[key]))
.filter(x => x)
.map(populateByProxy.bind(null, depth - 1, collections))
.reduce((res, item) => Object.assign({}, res, { [item.id]: item }), {});
}
if (collectionKeys.includes(plural(key))) {
return populateByProxy(
depth - 1,
collections,
getByIdFromCollection(collections[plural(key)])(value)
);
}
if (value && typeof value === 'object') {
return populateByProxy(depth, collections, value);
}
return value;
},
};
return Array.isArray(object) ? (
object.map((item) => populateByProxy(depth, collections, item))
) : (
new Proxy(object, handler)
);
}
const populatedNode = populate(depth, graph, obj)
const populatedPerson = populate(3, graph, graph.people[0])
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1'
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: {
stories: ['story-1'],
}
}
}
}
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: {
id: 'ted-chiang-1',
name: 'Ted Chiang',
likes: {
stories: [{
id: 'story-1',
name: 'Story of Your Life',
...
}],
}
}
}
}
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1',
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: {
stories: ['story-1'],
},
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1',
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: {
stories: ['story-1'],
},
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1',
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: {
stories: ['story-1'],
},
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1',
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: {
stories: ['story-1'],
},
},
{
...
}
];
const stories = [
{
id: 'story-1',
name: 'Story of Your Life',
author: {
person: 'ted-chiang-1',
}
},
{
...
}
];
const people = [
{
id: 'ted-chiang-1',
name: 'Ted Chiang',
authored: {
stories: ['story-1'],
},
},
{
...
}
];
const nameOfFirstLiker =
graph.stories[0].liked_by.people[0].name
const nameOfFirstLike =
graph.people[0].author.person.likes[0].name
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 ?
accessedProperty :
Undefined;
}
}
});
}
const neverUndefined = seatbelt({
});
const neverUndefined = seatbelt({
foo: 'bar',
baz: {
qux: 10,
name: 'yoyo',
},
});
neverUndefined.foo
neverUndefined.foo
// bar
neverUndefined.foo
// bar
neverUndefined.baz.qux
neverUndefined.foo
// bar
neverUndefined.baz.qux
// 10
neverUndefined.foo
// bar
neverUndefined.baz.qux
// 10
neverUndefined.baz.name
neverUndefined.foo
// bar
neverUndefined.baz.qux
// 10
neverUndefined.baz.name
// yoyo
neverUndefined
neverUndefined.notHere
neverUndefined.notHere.notAfunction
neverUndefined.notHere.notAfunction()
neverUndefined.notHere.notAfunction().nope
neverUndefined.notHere.notAfunction().nope
// [Function: Undefined]
neverUndefined.notHere.notAfunction().nope
// [Function: Undefined]
neverUndefined.foo.b.a.g.e.d().sf().d
neverUndefined.notHere.notAfunction().nope
// [Function: Undefined]
neverUndefined.foo.b.a.g.e.d().sf().d
// [Function: Undefined]
Object.prototype = seatbelt({});
/**
* Nobel prize material
*/
Object.prototype = seatbelt({});
By Eirik Langholm Vullum