Skip to content

Instantly share code, notes, and snippets.

@laphilosophia
Created November 5, 2018 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laphilosophia/ab3858ba3ee930f1651210f4b6ba609f to your computer and use it in GitHub Desktop.
Save laphilosophia/ab3858ba3ee930f1651210f4b6ba609f to your computer and use it in GitHub Desktop.
Object copy methods
// SHALLOW COPY
const obj1 = {
a: 1,
b: 2,
c: 'three',
d: new Date()
}
const obj2 = {
e: '1',
f: '2',
g: 3,
h: new Function()
}
const copySpread = { ...obj1,
...obj2
}
const copyAssign = Object.assign({}, obj1, obj2)
// DEEP COPY (WITH CAVEATS)
const obj3 = {
i: 0,
j: {
b: 1,
c: {
d: 0
}
}
}
const copiedObject = JSON.parse(JSON.stringify(obj3))
// DEEP COPY (WITH FEWER CAVEATS)
// Via MessageChannels:
class StructuredCloner {
constructor() {
this.pendingClones_ = new Map()
this.nextKey_ = 0
const channel = new MessageChannel()
this.inPort_ = channel.port1
this.outPort_ = channel.port2
this.outPort_.onmessage = ({
data: {
key,
value
}
}) => {
const resolve = this.pendingClones_.get(key)
resolve(value)
this.pendingClones_.delete(key)
}
this.outPort_.start()
}
cloneAsync(value) {
return new Promise(resolve => {
const key = this.nextKey_++
this.pendingClones_.set(key, resolve)
this.inPort_.postMessage({
key,
value
})
})
}
}
const structuredCloneAsync = window.structuredCloneAsync = StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner)
const main = async () => {
const original = {
date: new Date(),
number: Math.random()
}
original.self = original
const clone = await structuredCloneAsync(original)
// different objects:
console.assert(original !== clone)
console.assert(original.date !== clone.date)
// cyclical:
console.assert(original.self === original)
console.assert(clone.self === clone)
// equivalent values:
console.assert(original.number === clone.number)
console.assert(Number(original.date) === Number(clone.date))
console.log("Assertions complete.")
}
// Via the history API:
const structuredClone = obj => {
const oldState = history.state
history.replaceState(obj, null)
const clonedObj = history.state
history.replaceState(oldState, null)
return clonedObj
}
// Via the notification API:
const structuredClone = obj => {
const n = new Notification('', {
data: obj,
silent: true
})
n.onshow = n.close.bind(n)
return n.data
};
// DEEP COPY IN NODE.JS
``
`
Unfortunately again, the structured clone algorithm is currently
only available to browser based applications.
For the server side, one can use lodash's cloneDeep method, which
is also loosely based on the structured clone algorithm.
`
``
// CONCLUSION
function deepClone(obj) {
let copy
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj
// Handle Date
if (obj instanceof Date) {
copy = new Date()
copy.setTime(obj.getTime())
return copy
}
// Handle Array
if (obj instanceof Array) {
copy = []
for (let i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i])
}
return copy
}
// Handle Function
if (obj instanceof Function) {
copy = function () {
return obj.apply(this, arguments)
}
return copy
}
// Handle Object
if (obj instanceof Object) {
copy = {}
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr])
}
return copy
}
throw new Error("Unable to copy obj as type isn't supported " + obj.constructor.name)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment