Check out Distributed Systems with Node.js:bit.ly/34SHToF
Map
)const x = {
prop1: true
}
x.prop2 = 42
x['prop3'] = 'quux'
delete x.prop1
console.log(x.prop2) // 42
Object.defineProperty(
obj,
propertyName,
descriptors
)
const obj = {}
Object.defineProperty(obj, 'foo', {
value: 'hello', // the value of the property
enumerable: false // will the property be visible
})
console.log(obj) // {}
console.log(obj.foo) // 'hello'
console.log(Object.keys(obj)) // []
console.log(Reflect.ownKeys(obj)) // [ 'foo' ]
console.log('foo' in obj) // true
const obj = Object.defineProperty({}, 'foo', {
value: 'hello',
writable: false, // reassignable?
configurable: false // deletable/redefinable?
})
obj.foo = 'bye'
console.log(obj.foo) // 'hello'
delete obj.foo
console.log(obj.foo) // 'hello'
Object.defineProperty(obj, 'foo', {
value: 1
}) // TypeError: Cannot redefine property: foo
const obj = {realAge: null}
Object.defineProperty(obj, 'age', {
get: function() {
return Number(this.realAge)
},
set: function(value) {
this.realAge = Number(value)
}
})
console.log(obj.age) // 0
obj.age = '32'
console.log(obj.age) // 32
const obj = {
realAge: null,
get age() {
return Number(this.realAge)
},
set age(value) {
this.realAge = Number(value)
}
}
console.log(obj.age) // 0
obj.age = '32'
console.log(obj.age) // 32
// What code could lead to this outcome?
if (typeof obj.type === 'number' && obj.type > 10) {
console.log(obj.type) // 'not twelve'
}
let accesses = 0
const obj = Object.defineProperty({}, 'type', {
get: () => {
if (accesses++ >= 2) {
return 'not twelve'
}
return 12
}
})
// And how can you fix it?
if (typeof obj.type === 'number' && obj.type > 10) {
console.log(obj.type) // 'not twelve'
}
let accesses = 0
const obj = Object.defineProperty({}, 'type', {
get: () => {
if (accesses++ >= 2) {
return 'not twelve'
}
return 12
}
})
const type = obj.type // read sensitive values once
if (typeof type === 'number' && type > 10) {
console.log(type) // 12
}
const obj1 = {
a: 1
}
console.log(Object
.getOwnPropertyDescriptor(obj1, 'a'))
{
value: 1,
writable: true,
enumerable: true,
configurable: true
}
const obj2 = {
get b() { }
}
console.log(Object
.getOwnPropertyDescriptor(obj2, 'b'))
{
get: Function,
set: undefined,
enumerable: true,
configurable: true
}
const obj3 = Object.defineProperty({}, 'c', {
value: 'xyz'
})
console.log(Object
.getOwnPropertyDescriptor(obj3, 'c'))
{
value: 'xyz',
writable: false,
enumerable: false,
configurable: false
}
const obj = { p: 'hi' }
Object.seal(obj)
obj.p = 'bye' // OK
delete obj.p // disallowed
obj.p2 = 'new' // disallowed
console.log(obj) // { p: "bye" }
console.log(Object.isSealed(obj)) // true
console.log(Object.getOwnPropertyDescriptor(obj, 'p'))
// { value: "bye", writable: true,
// enumerable: true, configurable: false }
const obj = { p: 'bar' }
Object.preventExtensions(obj)
obj.x = true // fails silently
obj.p = 'bop' // OK
console.log(obj) // { p: "bar" }
console.log(Object.isExtensible(obj)) // false
console.log(Object.getOwnPropertyDescriptor(obj, 'p'))
// { value: "bop", writable: true,
// enumerable: true, configurable: true }
Object.defineProperty(obj, 'new', { value: 1 })
// ^ TypeError
const obj = { p: 'orig' }
Object.freeze(obj)
console.log(Object.isFrozen(obj)) // true
obj.p = 'new' // fail silently, throw in strict
delete obj.p // fail silently, throw in strict
obj.x = 1 // fail silently, throw in strict
console.log(obj) // { p: 'orig' }
console.log(Object.getOwnPropertyDescriptor(obj, 'p'))
// { value: "orig", writable: false,
// enumerable: true, configurable: false }
A Proxy is an object which lets you provide callable "trap" methods which are called when interacting with the object in various ways.
const proxy = new Proxy(target, handler)
const orig = { p: 7 }
const handler = {
get: (target, prop, receiver) => {
return target[prop] ? target[prop] + 1 : Infinity
}
}
const proxy = new Proxy(orig, handler)
console.log(orig.p) // 7
console.log(orig.r) // undefined
console.log(proxy.p) // 8
console.log(proxy.r) // Infinity
const orig = { p: 7 }
const handler = {
has: (target, prop) => {
return false
}
}
const proxy = new Proxy(orig, handler)
console.log('p' in orig) // true
console.log('r' in orig) // false
console.log('p' in proxy) // false
console.log(Reflect.has(proxy, 'p')) // false
console.log(proxy.p) // 7
const orig = {}
const handler = {
set: (target, prop, value, receiver) => {
target[prop.toUpperCase()] = String(value)
}
}
const proxy = new Proxy(orig, handler)
orig.p = 1
console.log(orig) // { p: 1 }
proxy.hello = 1
console.log(orig) // { p: 1, HELLO: '1' }
const obj = { p: 1, r: 2 }
const handler = {
deleteProperty: (target, prop) => {
if (prop === 'r') delete target[prop]
return true // falsey will throw in strict
}
}
const proxy = new Proxy(obj, handler)
delete proxy.p
delete proxy.r
console.log(proxy) // { p: 2 }
const sym = Symbol()
const orig = { p: 1, r: 2, [sym]: 3 }
const handler = {
ownKeys: (target) => ["p", sym]
}
const proxy = new Proxy(orig, handler)
console.log(Object.keys(proxy)) // ["p"]
console.log(Reflect.ownKeys(proxy)) // ["p",Symbol()]
console.log(Object
.getOwnPropertyNames(proxy)) // ["p"]
console.log(Object
.getOwnPropertySymbols(proxy)) // [Symbol()]
function orig(msg) {
return `Hello, ${msg}!`
}
const handler = {
apply: (target, self, args) => {
return target(String(args[0]).toUpperCase())
}
}
const proxy = new Proxy(orig, handler)
console.log(proxy('world')) // "Hello, WORLD!"
class Original {
constructor(arg) {
this.value = `Hello, ${arg}!`
}
}
const handler = {
construct(target, args) {
return new target(...args)
}
}
const proxy = new Proxy(Original, handler)
console.log(new proxy('Tom').value) // 'Hello, Tom!'
const orig = {}
const handler = {
getPrototypeOf: (target) => null,
setPrototypeOf: (target, proto) => {
throw new Error('no way')
}
}
const proxy = new Proxy(orig, handler)
console.log(orig.__proto__) // {}
console.log(proxy.__proto__) // null
console.log(Object.getPrototypeOf(proxy)) // null
console.log(Reflect.getPrototypeOf(proxy)) // null
proxy.__proto__ = {} // Error: no way
const orig = {}
const handler = {
preventExtensions: (target) =>
Object.preventExtensions(target),
isExtensible: (target) =>
Reflect.isExtensible(target)
}
const proxy = new Proxy(orig, handler)
console.log(Object.isExtensible(proxy)) // true
Object.preventExtensions(proxy)
console.log(Object.isExtensible(proxy)) // false
// Note: Can't lie, otherwise will throw Error
const proxy = new Proxy({}, {
defineProperty: (target, prop, desc) => {
if (desc.value === 42)
Object.defineProperty(target, prop, desc)
return true
},
getOwnPropertyDescriptor: (tgt, prp) => {
return Object.getOwnPropertyDescriptor(tgt, prp)
}
})
Object.defineProperty(proxy, 'p', { value: 42 })
Object.defineProperty(proxy, 'r', { value: 43 })
console.log(proxy.p, proxy.r) // 42, undefined
const orig = {}
Object.defineProperty(orig, 'name', {
get: () => {
console.log('2. prop desc get'); return 'Thomas'
}
})
const proxy = new Proxy(orig, {
get: (target, prop) => {
console.log('1. proxy get'); return target[prop]
}
})
console.log(`3. ${proxy.name}`) // 1. proxy get
// 2. prop desc get
// 3. Thomas
bit.ly/34SHToF