Native deep cloning
It's called "structured cloning", works experimentally in Node 11 and later, and hopefully will land in browsers. See this answer for more details.
Fast cloning with data loss - JSON.parse/stringify
If you do not use Date
s, functions, undefined
, Infinity
, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types within your object, a very simple one liner to deep clone an object is:
JSON.parse(JSON.stringify(object))
const a = {
string: 'string',
number: 123,
bool: false,
nul: null,
date: new Date(), // stringified
undef: undefined, // lost
inf: Infinity, // forced to 'null'
re: /.*/, // lost
}
console.log(a);
console.log(typeof a.date); // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date); // result of .toISOString()
See Corban's answer for benchmarks.
Reliable cloning using a library
Since cloning objects is not trivial (complex types, circular references, function etc.), most major libraries provide function to clone objects. Don't reinvent the wheel - if you're already using a library, check if it has an object cloning function. For example,
- lodash -
cloneDeep
; can be imported separately via the lodash.clonedeep module and is probably your best choice if you're not already using a library that provides a deep cloning function
- AngularJS -
angular.copy
- jQuery -
jQuery.extend(true, { }, oldObject)
; .clone()
only clones DOM elements
- just library -
just-clone
; Part of a library of zero-dependency npm modules that do just do one thing.
Guilt-free utilities for every occasion.
ES6 (shallow copy)
For completeness, note that ES6 offers two shallow copy mechanisms: Object.assign()
and the spread syntax.
which copies values of all enumerable own properties from one object to another. For example:
var A1 = {a: "2"};
var A2 = Object.assign({}, A1);
var A3 = {...A1}; // Spread Syntax
Short & Snazzy:
+ new Date()
A unary operator like plus
triggers the valueOf
method in the Date
object and it returns the timestamp (without any alteration).
Details:
On almost all current browsers you can use Date.now()
to get the UTC timestamp in milliseconds; a notable exception to this is IE8 and earlier (see compatibility table).
You can easily make a shim for this, though:
if (!Date.now) {
Date.now = function() { return new Date().getTime(); }
}
To get the timestamp in seconds, you can use:
Math.floor(Date.now() / 1000)
Or alternatively you could use:
Date.now() / 1000 | 0
Which should be slightly faster, but also less readable.
(also see this answer or this with further explaination to bitwise operators).
I would recommend using Date.now()
(with compatibility shim). It's slightly better because it's shorter & doesn't create a new Date
object. However, if you don't want a shim & maximum compatibility, you could use the "old" method to get the timestamp in milliseconds:
new Date().getTime()
Which you can then convert to seconds like this:
Math.round(new Date().getTime()/1000)
And you can also use the valueOf
method which we showed above:
new Date().valueOf()
Timestamp in Milliseconds
var timeStampInMs = window.performance && window.performance.now && window.performance.timing && window.performance.timing.navigationStart ? window.performance.now() + window.performance.timing.navigationStart : Date.now();
console.log(timeStampInMs, Date.now());
Best Answer
If we split it up, the mess is equal to:
In JavaScript, it is true that
+[] === 0
.+
converts something into a number, and in this case it will come down to+""
or0
(see specification details below).Therefore, we can simplify it (
++
has precendence over+
):Because
[[]][0]
means: get the first element from[[]]
, it is true that:[[]][0]
returns the inner array ([]
). Due to references it's wrong to say[[]][0] === []
, but let's call the inner arrayA
to avoid the wrong notation.++
before its operand means “increment by one and return the incremented result”. So++[[]][0]
is equivalent toNumber(A) + 1
(or+A + 1
).Again, we can simplify the mess into something more legible. Let's substitute
[]
back forA
:Before
+[]
can coerce the array into the number0
, it needs to be coerced into a string first, which is""
, again. Finally,1
is added, which results in1
.(+[] + 1) === (+"" + 1)
(+"" + 1) === (0 + 1)
(0 + 1) === 1
Let's simplify it even more:
Also, this is true in JavaScript:
[0] == "0"
, because it's joining an array with one element. Joining will concatenate the elements separated by,
. With one element, you can deduce that this logic will result in the first element itself.In this case,
+
sees two operands: a number and an array. It’s now trying to coerce the two into the same type. First, the array is coerced into the string"0"
, next, the number is coerced into a string ("1"
). Number+
String===
String.Specification details for
+[]
:This is quite a maze, but to do
+[]
, first it is being converted to a string because that's what+
says:ToNumber()
says:ToPrimitive()
says:[[DefaultValue]]
says:The
.toString
of an array says:So
+[]
comes down to+""
, because[].join() === ""
.Again, the
+
is defined as:ToNumber
is defined for""
as:So
+"" === 0
, and thus+[] === 0
.