Slide navigation: Forward with space bar, →, or PgDn. Backwards with ← or PgUp.
writable: When true, can update the value.enumerable: When true, is visited in for in loop.configurable: When true, ok to delete and to modify these three attributes.true in object literals or dynamically added properties, false in calls to defineProperty/defineProperties.defineProperty to set the attributes:
Object.defineProperty(james, 'id', {
value: '007',
enumerable: true,
writable: false,
configurable: true
})
definePropertyget and set attributes hold getter/setter functions.Object.defineProperties(james, { id: { ... }, age: { ... }})const sym = Symbol('label')
sym !== Symbol('label')typeof sym is 'symbol'obj[sym] = value
{[sym]: value}
Symbol.iterator, Symbol.species, ...Symbol.for('com.horstmann.label')Object.getOwnPropertyDescriptor(harry, 'id') →
{ value: 42, enumerable: true, writable: false, configurable: true }obj.hasOwnProperty(stringOrSymbol) is true if obj has a property with the given key.
obj[stringOrSymbol] is undefined, the property might be absent or have the value undefined.obj.propertyIsEnumerable(stringOrSymbol) is true if obj has an enumerable property with the given key.Object.keys(obj), Object.values(obj), Object.entries(obj)
[key, value] pairs.Object.getOwnPropertyNames(obj), Object.getOwnPropertySymbols(obj)
Object.getOwnPropertyDescriptors(obj) gets all property descriptors.Object.create(prototype, propertyDescriptors) creates an object with the given prototype and properties.Object.fromEntries constructs an object from an iterable of key/value pair arrays:
let james = Object.fromEntries([['name', 'James Bond'], ['id', '007']])
Object.assign(target, ...source) copies all enumerable own properties from the sources into the target and returns the updated target:
james = Object.assign(james, { salary: 300000}, { buddy: 'Harry Smith'})
Object.preventExtensions(obj): Can't add properties.Object.seal(obj): Can't add or delete properties, can't configure existing properties. Object.freeze(obj): In addition, can't set properties, can't change prototype.return Object.freeze({ ... })
Object.isExtensible(obj), Object.isSealed(obj), Object.isFrozen(obj)Object.create(proto) creates a new object and sets its [[Prototype]] to proto.Object.getPrototypeOf(obj) gets the [[Prototype]].proto.isPrototypeOf(obj) is true if proto is in the prototype chain of obj.
obj instanceof C is the same as C.prototype.isPrototypeOf(obj)Object.setPrototypeOf(obj, proto) updates the prototype.
Object.create method.prototype property.{ constructor: function } when function is defined.
constructor property not enumerable.obj = new function, the [[Prototype]] of obj is set to function.prototype. 
constructor Property, new.targetclass syntax, subclasses set constructor manually.Object.getPrototypeOf(obj) safer than obj.constructor.prototype
Object.create(null) does not have constructor.constructorobj = new function, new.target is set to function
new (new.target === undefined)new.target === function) Object MethodstoString called whenever an object must be turned into a string:
'Hello ' + obj
`Hello ${obj}`
String(obj)
obj.toString() returns [object Constructor name]toString to produce a better description.toLocaleString calls toString, can be overridden to produce a locale-specific description.valueOf if you want to produce a primitive type value that is used in arithmetic expressions.
Date overrides valueOf to return the number of milliseconds since the epoch:
new Date(2525,0,1) - new Date(2000,0,1) → 16567459200000
Object.is(x, y) is almost the same as x === y, except that Object.is(+0, -0) is false and Object.is(NaN, NaN) is true.name of a Function object is the name with which the function was defined.length is the number of arguments (not counting a rest argument)bind lets you “curry” a function by specifying its initial arguments:
function multiply(x, y) { return x * y }
const double = multiply.bind(null, 2)
double(42) → 84
this
const isPet = Array.prototype.includes.bind(['cat', 'dog', 'fish'])
// Same as x => ['cat', 'dog', 'fish'].includes(x)this in a callback to another method of the same class:
button.onclick = this.handleClick.bind(this)
button.onclick = (...args) => this.handleClick(...args)
call and apply invoke functions and methods programmatically.f(args) or obj.f(args)?call calls a method with a different this:
while (Array.prototype.includes.call('aeiou', str[i])) i++
// Can't call 'aeiou'.includes(str[i])—includes isn't defined for strings!
apply is like call, but the arguments other than this are in an array.const proxy = new Proxy(obj, handler): Operations on obj are trapped by the handler.{
get: (target, key, receiver) => { ... },
set: (target, key, value, receiver) => { ... }
...
}
target is obj, receiver is the object whose property was accessed (proxy unless the proxy is in the prototype chain).const logHandler = {
...
set: (target, key, value, receiver) => {
console.log(`set '${key}' to ${value}`)
target[key] = value
}
}const values = new Proxy([1, 2, 3], logHandler)
values[2] = 4 // Console logs set '2' to 4
Proxy.revocable(obj, handler) returns object with proxy object and revoke function:
const mySomewhatSensitiveObject = ...
const p = Proxy.revocable(mySomewhatSensitiveObject, {})
doSomethingWith(p.proxy)
p.revoke()
// p.proxy is no longer usable
get(target, key, receiver) |
receiver[key], receiver.key |
set(target, key, value, receiver) |
receiver[key] = value, receiver.key = value |
deleteProperty(target, property) |
delete proxy[key], delete proxy.key |
has(target, key) |
key in target |
getPrototypeOf(target) |
Object.getPrototypeOf(proxy) |
setPrototypeOf(target, proto) |
Object.setPrototypeOf(proxy, proto) |
isExtensible(target) |
Object.isExtensible(proxy) |
preventExtensions(target) |
Object.preventExtensions(proxy) |
getOwnPropertyDescriptor(target, key) |
Object.getOwnPropertyDescriptor(proxy, key) |
ownKeys(target) |
Object.keys(proxy) (also calling getOwnPropertyDescriptor), Object.getOwnPropertyProperty(Names|Symbols)(proxy) |
defineProperty(target, key, descriptor) |
Object.defineProperty(proxy, key, descriptor) |
apply(target, thisArg, args) |
thisArg.proxy(...args), proxy(...args), proxy.apply(thisArg, args), proxy.call(thisArg, ...args) |
construct(target, args, newTarget) |
new proxy(args), or invocation through super |
Reflect implements the twelve trap operations.const logHandler = {
...
set: (target, key, value, receiver) => {
console.log(`set '${key}' to ${value}`)
Reflect.set(target, key, value, receiver)
}
}const logHandler = new Proxy({}, {
get(target, trapKey, receiver) {
return (...args) => {
console.log(`${trapKey} ${args}`)
return Reflect[trapKey](...args);
}
}
})Reflect operations are more convenient than their explicit analogs.
Reflect.deleteProperty returns a boolean to tell whether deletion was successful, delete operator doesn't.Reflect.defineProperty returns a boolean, Object.defineProperty throws an exception upon failure.Reflect.apply(f, thisArg, args) calls Function.apply, f.apply(thisArg, args) might not (if f.apply was redefined).construct must return an object.getOwnPropertyDescriptor must return a descriptor object or undefinedgetPrototypeOf must return an object or nullget operation of a proxy must yield the actual value.TypeError is thrown.has cannot hide it.getPrototypeOf operation must yield the actual prototype, and has an getOwnPropertyDescriptor must report the actual properties.toString, Object.toString returns '[object Object]'Object.toString by defining a property with key Symbol.toStringTag
class Employee {
get [Symbol.toStringTag]() { return 'Employee' }
}
Object.toString yields '[object Employee]'get [Symbol.toStringTag]() { return this.constructor.name }
get [Symbol.toStringTag]() { return JSON.stringify(this) }toString/valueOf:
class Percent {
constructor(rate) { this.rate = rate }
toString() { return `${this.rate}%` }
valueOf() { return this.rate * 0.01 }
}'' + new Percent(99.44) → '0.9944'
'99.44%'?Symbol.toPrimitive
[Symbol.toPrimitive](hint) {
if (hint === 'number') return this.rate * 0.01
else return `${this.rate}%`
}
'number' with arithmetic other than + and comparisons'string' with ` ${...} ` or String(...)'default' with + or ==Array method map produces the same collection that it received:
class MyArray extends Array {}
let myValues = new MyArray(1, 2, 7, 9)
myValues.map(x => x * x) // Yields a MyArrayclass Range extends Array
Symbol.species key:
class Range extends Array {
static get [Symbol.species]() { return Array }
...
}
Symbol.iterator, Symbol.asyncIterator—see the lessons on Iterators/Asynchronous Programminginstanceof with Symbol.hasInstance
class Iterable {
static [Symbol.hasInstance](obj) { return Symbol.iterator in obj }
}
[1, 2, 3] instanceof Iterable
Symbol.isConcatSpreadable is used in the concat method of Array
const a = [1, 2] const b = [3, 4] a[Symbol.isConcatSpreadable] = false [].concat(a, b) ⇒ [[1, 2], 3, 4]
Symbol.match, Symbol.replace, Symbol.search, Symbol.split are called from the String methods with the same name.