stored exponential value in mongodb [duplicate] - node.js
I'm looking for a good JavaScript equivalent of the C/PHP printf() or for C#/Java programmers, String.Format() (IFormatProvider for .NET).
My basic requirement is a thousand separator format for numbers for now, but something that handles lots of combinations (including dates) would be good.
I realize Microsoft's Ajax library provides a version of String.Format(), but we don't want the entire overhead of that framework.
Current JavaScript
From ES6 on you could use template strings:
let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!"
See Kim's answer below for details.
Older answer
Try sprintf() for JavaScript.
If you really want to do a simple format method on your own, don’t do the replacements successively but do them simultaneously.
Because most of the other proposals that are mentioned fail when a replace string of previous replacement does also contain a format sequence like this:
"{0}{1}".format("{1}", "{0}")
Normally you would expect the output to be {1}{0} but the actual output is {1}{1}. So do a simultaneous replacement instead like in fearphage’s suggestion.
Building on the previously suggested solutions:
// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
}
"{0} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")
outputs
ASP is dead, but ASP.NET is alive! ASP {2}
If you prefer not to modify String's prototype:
if (!String.format) {
String.format = function(format) {
var args = Array.prototype.slice.call(arguments, 1);
return format.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
}
Gives you the much more familiar:
String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');
with the same result:
ASP is dead, but ASP.NET is alive! ASP {2}
It's funny because Stack Overflow actually has their own formatting function for the String prototype called formatUnicorn. Try it! Go into the console and type something like:
"Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"});
You get this output:
Hello, Gabriel, are you feeling OK?
You can use objects, arrays, and strings as arguments! I got its code and reworked it to produce a new version of String.prototype.format:
String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
function () {
"use strict";
var str = this.toString();
if (arguments.length) {
var t = typeof arguments[0];
var key;
var args = ("string" === t || "number" === t) ?
Array.prototype.slice.call(arguments)
: arguments[0];
for (key in args) {
str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
}
}
return str;
};
Note the clever Array.prototype.slice.call(arguments) call -- that means if you throw in arguments that are strings or numbers, not a single JSON-style object, you get C#'s String.Format behavior almost exactly.
"a{0}bcd{1}ef".formatUnicorn("FOO", "BAR"); // yields "aFOObcdBARef"
That's because Array's slice will force whatever's in arguments into an Array, whether it was originally or not, and the key will be the index (0, 1, 2...) of each array element coerced into a string (eg, "0", so "\\{0\\}" for your first regexp pattern).
Neat.
Number Formatting in JavaScript
I got to this question page hoping to find how to format numbers in JavaScript, without introducing yet another library. Here's what I've found:
Rounding floating-point numbers
The equivalent of sprintf("%.2f", num) in JavaScript seems to be num.toFixed(2), which formats num to 2 decimal places, with rounding (but see #ars265's comment about Math.round below).
(12.345).toFixed(2); // returns "12.35" (rounding!)
(12.3).toFixed(2); // returns "12.30" (zero padding)
Exponential form
The equivalent of sprintf("%.2e", num) is num.toExponential(2).
(33333).toExponential(2); // "3.33e+4"
Hexadecimal and other bases
To print numbers in base B, try num.toString(B). JavaScript supports automatic conversion to and from bases 2 through 36 (in addition, some browsers have limited support for base64 encoding).
(3735928559).toString(16); // to base 16: "deadbeef"
parseInt("deadbeef", 16); // from base 16: 3735928559
Reference Pages
Quick tutorial on JS number formatting
Mozilla reference page for toFixed() (with links to toPrecision(), toExponential(), toLocaleString(), ...)
From ES6 on you could use template strings:
let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!"
Be aware that template strings are surrounded by backticks ` instead of (single) quotes.
For further information:
https://developers.google.com/web/updates/2015/01/ES6-Template-Strings
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings
Note:
Check the mozilla-site to find a list of supported browsers.
jsxt, Zippo
This option fits better.
String.prototype.format = function() {
var formatted = this;
for (var i = 0; i < arguments.length; i++) {
var regexp = new RegExp('\\{'+i+'\\}', 'gi');
formatted = formatted.replace(regexp, arguments[i]);
}
return formatted;
};
With this option I can replace strings like these:
'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');
With your code the second {0} wouldn't be replaced. ;)
I use this simple function:
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
That's very similar to string.format:
"{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")
For Node.js users there is util.format which has printf-like functionality:
util.format("%s world", "Hello")
I'm surprised no one used reduce, this is a native concise and powerful JavaScript function.
ES6 (EcmaScript2015)
String.prototype.format = function() {
return [...arguments].reduce((p,c) => p.replace(/%s/,c), this);
};
console.log('Is that a %s or a %s?... No, it\'s %s!'.format('plane', 'bird', 'SOman'));
< ES6
function interpolate(theString, argumentArray) {
var regex = /%s/;
var _r=function(p,c){return p.replace(regex,c);}
return argumentArray.reduce(_r, theString);
}
interpolate("%s, %s and %s", ["Me", "myself", "I"]); // "Me, myself and I"
How it works:
reduce applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
var _r= function(p,c){return p.replace(/%s/,c)};
console.log(
["a", "b", "c"].reduce(_r, "[%s], [%s] and [%s]") + '\n',
[1, 2, 3].reduce(_r, "%s+%s=%s") + '\n',
["cool", 1337, "stuff"].reduce(_r, "%s %s %s")
);
Here's a minimal implementation of sprintf in JavaScript: it only does "%s" and "%d", but I have left space for it to be extended. It is useless to the OP, but other people who stumble across this thread coming from Google might benefit from it.
function sprintf() {
var args = arguments,
string = args[0],
i = 1;
return string.replace(/%((%)|s|d)/g, function (m) {
// m is the matched format, e.g. %s, %d
var val = null;
if (m[2]) {
val = m[2];
} else {
val = args[i];
// A switch statement so that the formatter can be extended. Default is %s
switch (m) {
case '%d':
val = parseFloat(val);
if (isNaN(val)) {
val = 0;
}
break;
}
i++;
}
return val;
});
}
Example:
alert(sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two'));
// Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0
In contrast with similar solutions in previous replies, this one does all substitutions in one go, so it will not replace parts of previously replaced values.
3 different ways to format javascript string
There are 3 different ways to format a string by replacing placeholders with the variable value.
Using template literal (backticks ``)
let name = 'John';
let age = 30;
// using backticks
console.log(`${name} is ${age} years old.`);
// John is 30 years old.
Using concatenation
let name = 'John';
let age = 30;
// using concatenation
console.log(name + ' is ' + age + ' years old.');
// John is 30 years old.
Creating own format function
String.prototype.format = function () {
var args = arguments;
return this.replace(/{([0-9]+)}/g, function (match, index) {
// check if the argument is there
return typeof args[index] == 'undefined' ? match : args[index];
});
};
console.log('{0} is {1} years old.'.format('John', 30));
JavaScript programmers can use String.prototype.sprintf at https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js. Below is example:
var d = new Date();
var dateStr = '%02d:%02d:%02d'.sprintf(
d.getHours(),
d.getMinutes(),
d.getSeconds());
I want to share my solution for the 'problem'. I haven't re-invented the wheel but tries to find a solution based on what JavaScript already does. The advantage is, that you get all implicit conversions for free. Setting the prototype property $ of String gives a very nice and compact syntax (see examples below). It is maybe not the most efficient way, but in most cases dealing with output it does not have to be super optimized.
String.form = function(str, arr) {
var i = -1;
function callback(exp, p0, p1, p2, p3, p4) {
if (exp=='%%') return '%';
if (arr[++i]===undefined) return undefined;
exp = p2 ? parseInt(p2.substr(1)) : undefined;
var base = p3 ? parseInt(p3.substr(1)) : undefined;
var val;
switch (p4) {
case 's': val = arr[i]; break;
case 'c': val = arr[i][0]; break;
case 'f': val = parseFloat(arr[i]).toFixed(exp); break;
case 'p': val = parseFloat(arr[i]).toPrecision(exp); break;
case 'e': val = parseFloat(arr[i]).toExponential(exp); break;
case 'x': val = parseInt(arr[i]).toString(base?base:16); break;
case 'd': val = parseFloat(parseInt(arr[i], base?base:10).toPrecision(exp)).toFixed(0); break;
}
val = typeof(val)=='object' ? JSON.stringify(val) : val.toString(base);
var sz = parseInt(p1); /* padding size */
var ch = p1 && p1[0]=='0' ? '0' : ' '; /* isnull? */
while (val.length<sz) val = p0 !== undefined ? val+ch : ch+val; /* isminus? */
return val;
}
var regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g;
return str.replace(regex, callback);
}
String.prototype.$ = function() {
return String.form(this, Array.prototype.slice.call(arguments));
}
Here are a few examples:
String.format("%s %s", [ "This is a string", 11 ])
console.log("%s %s".$("This is a string", 11))
var arr = [ "12.3", 13.6 ]; console.log("Array: %s".$(arr));
var obj = { test:"test", id:12 }; console.log("Object: %s".$(obj));
console.log("%c", "Test");
console.log("%5d".$(12)); // ' 12'
console.log("%05d".$(12)); // '00012'
console.log("%-5d".$(12)); // '12 '
console.log("%5.2d".$(123)); // ' 120'
console.log("%5.2f".$(1.1)); // ' 1.10'
console.log("%10.2e".$(1.1)); // ' 1.10e+0'
console.log("%5.3p".$(1.12345)); // ' 1.12'
console.log("%5x".$(45054)); // ' affe'
console.log("%20#2x".$("45054")); // ' 1010111111111110'
console.log("%6#2d".$("111")); // ' 7'
console.log("%6#16d".$("affe")); // ' 45054'
Adding to zippoxer's answer, I use this function:
String.prototype.format = function () {
var a = this, b;
for (b in arguments) {
a = a.replace(/%[a-z]/, arguments[b]);
}
return a; // Make chainable
};
var s = 'Hello %s The magic number is %d.';
s.format('world!', 12); // Hello World! The magic number is 12.
I also have a non-prototype version which I use more often for its Java-like syntax:
function format() {
var a, b, c;
a = arguments[0];
b = [];
for(c = 1; c < arguments.length; c++){
b.push(arguments[c]);
}
for (c in b) {
a = a.replace(/%[a-z]/, b[c]);
}
return a;
}
format('%d ducks, 55 %s', 12, 'cats'); // 12 ducks, 55 cats
ES 2015 update
All the cool new stuff in ES 2015 makes this a lot easier:
function format(fmt, ...args){
return fmt
.split("%%")
.reduce((aggregate, chunk, i) =>
aggregate + chunk + (args[i] || ""), "");
}
format("Hello %%! I ate %% apples today.", "World", 44);
// "Hello World, I ate 44 apples today."
I figured that since this, like the older ones, doesn't actually parse the letters, it might as well just use a single token %%. This has the benefit of being obvious and not making it difficult to use a single %. However, if you need %% for some reason, you would need to replace it with itself:
format("I love percentage signs! %%", "%%");
// "I love percentage signs! %%"
+1 Zippo with the exception that the function body needs to be as below or otherwise it appends the current string on every iteration:
String.prototype.format = function() {
var formatted = this;
for (var arg in arguments) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
I use a small library called String.format for JavaScript which supports most of the format string capabilities (including format of numbers and dates), and uses the .NET syntax. The script itself is smaller than 4 kB, so it doesn't create much of overhead.
I'll add my own discoveries which I've found since I asked:
number_format (for thousand separator/currency formatting)
sprintf (same author as above)
Sadly it seems sprintf doesn't handle thousand separator formatting like .NET's string format.
If you are looking to handle the thousands separator, you should really use toLocaleString() from the JavaScript Number class since it will format the string for the user's region.
The JavaScript Date class can format localized dates and times.
Very elegant:
String.prototype.format = function (){
var args = arguments;
return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (curlyBrack, index) {
return ((curlyBrack == "{{") ? "{" : ((curlyBrack == "}}") ? "}" : args[index]));
});
};
// Usage:
"{0}{1}".format("{1}", "{0}")
Credit goes to (broken link) https://gist.github.com/0i0/1519811
There is "sprintf" for JavaScript which you can find at http://www.webtoolkit.info/javascript-sprintf.html.
The PHPJS project has written JavaScript implementations for many of PHP's functions. Since PHP's sprintf() function is basically the same as C's printf(), their JavaScript implementation of it should satisfy your needs.
I use this one:
String.prototype.format = function() {
var newStr = this, i = 0;
while (/%s/.test(newStr))
newStr = newStr.replace("%s", arguments[i++])
return newStr;
}
Then I call it:
"<h1>%s</h1><p>%s</p>".format("Header", "Just a test!");
I have a solution very close to Peter's, but it deals with number and object case.
if (!String.prototype.format) {
String.prototype.format = function() {
var args;
args = arguments;
if (args.length === 1 && args[0] !== null && typeof args[0] === 'object') {
args = args[0];
}
return this.replace(/{([^}]*)}/g, function(match, key) {
return (typeof args[key] !== "undefined" ? args[key] : match);
});
};
}
Maybe it could be even better to deal with the all deeps cases, but for my needs this is just fine.
"This is an example from {name}".format({name:"Blaine"});
"This is an example from {0}".format("Blaine");
PS: This function is very cool if you are using translations in templates frameworks like AngularJS:
<h1> {{('hello-message'|translate).format(user)}} <h1>
<h1> {{('hello-by-name'|translate).format( user ? user.name : 'You' )}} <h1>
Where the en.json is something like
{
"hello-message": "Hello {name}, welcome.",
"hello-by-name": "Hello {0}, welcome."
}
One very slightly different version, the one I prefer (this one uses {xxx} tokens rather than {0} numbered arguments, this is much more self-documenting and suits localization much better):
String.prototype.format = function(tokens) {
var formatted = this;
for (var token in tokens)
if (tokens.hasOwnProperty(token))
formatted = formatted.replace(RegExp("{" + token + "}", "g"), tokens[token]);
return formatted;
};
A variation would be:
var formatted = l(this);
that calls an l() localization function first.
For basic formatting:
var template = jQuery.validator.format("{0} is not a valid value");
var result = template("abc");
We can use a simple lightweight String.Format string operation library for Typescript.
String.Format():
var id = image.GetId()
String.Format("image_{0}.jpg", id)
output: "image_2db5da20-1c5d-4f1a-8fd4-b41e34c8c5b5.jpg";
String Format for specifiers:
var value = String.Format("{0:L}", "APPLE"); //output "apple"
value = String.Format("{0:U}", "apple"); // output "APPLE"
value = String.Format("{0:d}", "2017-01-23 00:00"); //output "23.01.2017"
value = String.Format("{0:s}", "21.03.2017 22:15:01") //output "2017-03-21T22:15:01"
value = String.Format("{0:n}", 1000000);
//output "1.000.000"
value = String.Format("{0:00}", 1);
//output "01"
String Format for Objects including specifiers:
var fruit = new Fruit();
fruit.type = "apple";
fruit.color = "RED";
fruit.shippingDate = new Date(2018, 1, 1);
fruit.amount = 10000;
String.Format("the {type:U} is {color:L} shipped on {shippingDate:s} with an amount of {amount:n}", fruit);
// output: the APPLE is red shipped on 2018-01-01 with an amount of 10.000
Just in case someone needs a function to prevent polluting global scope, here is the function that does the same:
function _format (str, arr) {
return str.replace(/{(\d+)}/g, function (match, number) {
return typeof arr[number] != 'undefined' ? arr[number] : match;
});
};
For those who like Node.JS and its util.format feature, I've just extracted it out into its vanilla JavaScript form (with only functions that util.format uses):
exports = {};
function isString(arg) {
return typeof arg === 'string';
}
function isNull(arg) {
return arg === null;
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isBoolean(arg) {
return typeof arg === 'boolean';
}
function isUndefined(arg) {
return arg === void 0;
}
function stylizeNoColor(str, styleType) {
return str;
}
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][3] + 'm';
} else {
return str;
}
}
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isSymbol(arg) {
return typeof arg === 'symbol';
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value)) {
// Format -0 as '-0'. Strict equality won't distinguish 0 from -0,
// so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 .
if (value === 0 && 1 / value < 0)
return ctx.stylize('-0', 'number');
return ctx.stylize('' + value, 'number');
}
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
// es6 symbol primitive
if (isSymbol(value))
return ctx.stylize(value.toString(), 'symbol');
}
function arrayToHash(array) {
var hash = {};
array.forEach(function (val, idx) {
hash[val] = true;
});
return hash;
}
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatPrimitiveNoColor(ctx, value) {
var stylize = ctx.stylize;
ctx.stylize = stylizeNoColor;
var str = formatPrimitive(ctx, value);
ctx.stylize = stylize;
return str;
}
function isArray(ar) {
return Array.isArray(ar);
}
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || {value: value[key]};
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function (line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function (line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'")
.replace(/\\\\/g, '\\');
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function (key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function reduceToSingleString(output, base, braces) {
var length = output.reduce(function (prev, cur) {
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// This could be a boxed primitive (new String(), etc.), check valueOf()
// NOTE: Avoid calling `valueOf` on `Date` instance because it will return
// a number which, when object has some additional user-stored `keys`,
// will be printed out.
var formatted;
var raw = value;
try {
// the .valueOf() call can fail for a multitude of reasons
if (!isDate(value))
raw = value.valueOf();
} catch (e) {
// ignore...
}
if (isString(raw)) {
// for boxed Strings, we have to remove the 0-n indexed entries,
// since they just noisey up the output and are redundant
keys = keys.filter(function (key) {
return !(key >= 0 && key < raw.length);
});
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
// now check the `raw` value to handle boxed primitives
if (isString(raw)) {
formatted = formatPrimitiveNoColor(ctx, raw);
return ctx.stylize('[String: ' + formatted + ']', 'string');
}
if (isNumber(raw)) {
formatted = formatPrimitiveNoColor(ctx, raw);
return ctx.stylize('[Number: ' + formatted + ']', 'number');
}
if (isBoolean(raw)) {
formatted = formatPrimitiveNoColor(ctx, raw);
return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean');
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
// Make boxed primitive Strings look like such
if (isString(raw)) {
formatted = formatPrimitiveNoColor(ctx, raw);
base = ' ' + '[String: ' + formatted + ']';
}
// Make boxed primitive Numbers look like such
if (isNumber(raw)) {
formatted = formatPrimitiveNoColor(ctx, raw);
base = ' ' + '[Number: ' + formatted + ']';
}
// Make boxed primitive Booleans look like such
if (isBoolean(raw)) {
formatted = formatPrimitiveNoColor(ctx, raw);
base = ' ' + '[Boolean: ' + formatted + ']';
}
if (keys.length === 0 && (!array || value.length === 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function (key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold': [1, 22],
'italic': [3, 23],
'underline': [4, 24],
'inverse': [7, 27],
'white': [37, 39],
'grey': [90, 39],
'black': [30, 39],
'blue': [34, 39],
'cyan': [36, 39],
'green': [32, 39],
'magenta': [35, 39],
'red': [31, 39],
'yellow': [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'symbol': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
var formatRegExp = /%[sdj%]/g;
exports.format = function (f) {
if (!isString(f)) {
var objects = [];
for (var j = 0; j < arguments.length; j++) {
objects.push(inspect(arguments[j]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function (x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s':
return String(args[i++]);
case '%d':
return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
Harvested from: https://github.com/joyent/node/blob/master/lib/util.js
I have a slightly longer formatter for JavaScript here...
You can do formatting several ways:
String.format(input, args0, arg1, ...)
String.format(input, obj)
"literal".format(arg0, arg1, ...)
"literal".format(obj)
Also, if you have say a ObjectBase.prototype.format (such as with DateJS) it will use that.
Examples...
var input = "numbered args ({0}-{1}-{2}-{3})";
console.log(String.format(input, "first", 2, new Date()));
//Outputs "numbered args (first-2-Thu May 31 2012...Time)-{3})"
console.log(input.format("first", 2, new Date()));
//Outputs "numbered args(first-2-Thu May 31 2012...Time)-{3})"
console.log(input.format(
"object properties ({first}-{second}-{third:yyyy-MM-dd}-{fourth})"
,{
'first':'first'
,'second':2
,'third':new Date() //assumes Date.prototype.format method
}
));
//Outputs "object properties (first-2-2012-05-31-{3})"
I've also aliased with .asFormat and have some detection in place in case there's already a string.format (such as with MS Ajax Toolkit (I hate that library).
Using Lodash you can get template functionality:
Use the ES template literal delimiter as an "interpolate" delimiter.
Disable support by replacing the "interpolate" delimiter.
var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!
Related
How to find all words that "contain" or "unscramble" an input string using a Trie?
Here is a trie made to work on alphabets/scripts from any language. class TrieNode { constructor(key) { // the "key" value will be the character in sequence this.key = key; // we keep a reference to parent this.parent = null; // we have hash of children this.children = {}; // check to see if the node is at the end this.end = false; } getWord() { let output = []; let node = this; while (node !== null) { output.unshift(node.key) node = node.parent } return output.join('') } } class Trie { constructor() { this.base = new TrieNode(null) } insert(word) { let node = this.base const points = Array.from(word) for (const i in points) { const point = points[i] if (!node.children[point]) { const child = node.children[point] = new TrieNode(point) child.parent = node } node = node.children[point] if (i == word.length - 1) { node.end = true } } } contains(word) { let node = this.base const points = Array.from(word) for (const i in points) { const point = points[i] if (node.children[point]) { node = node.children[point] } else { return false } } return node.end; } find(prefix) { let node = this.base let output = [] const points = Array.from(prefix) for (const i in points) { const point = points[i] // make sure prefix actually has words if (node.children[point]) { node = node.children[point] } else { // there's none. just return it. return output } } const stack = [node] while (stack.length) { node = stack.shift() // base case, if node is at a word, push to output if (node.end) { output.unshift(node.getWord()) } // iterate through each children, call recursive findAllWords for (var child in node.children) { stack.push(node.children[child]) } } return output } } After asking How to efficiently store 1 million words and query them by starts_with, contains, or ends_with? and getting some answers, I am wondering how the "contains" and "unscrambles" parts can be implemented as a trie. The prefix ("starts with") search is easily handled by the trie. const fs = require('fs') const Trie = require('./Trie') const words = fs.readFileSync('tmp/scrabble.csv', 'utf-8') .trim() .split(/\n+/) .map(x => x.trim()) const trie = new Trie() words.forEach(word => trie.insert(word)) console.log(trie.find('zy')) [ 'zygodactylous', 'zygomorphies', 'zygapophysis', 'zygapophyses', 'zygomorphic', 'zymologies', 'zygospores', 'zygosities', 'zygomorphy', 'zygodactyl', 'zymurgies', 'zymograms', 'zymogenes', 'zygotenes', 'zygospore', 'zygomatic', 'zyzzyvas', 'zymosans', 'zymology', 'zymogram', 'zymogens', 'zymogene', 'zygotene', 'zygosity', 'zygomata', 'zyzzyva', 'zymurgy', 'zymotic', 'zymosis', 'zymoses', 'zymosan', 'zymogen', 'zymases', 'zygotic', 'zygotes', 'zygosis', 'zygoses', 'zygomas', 'zydecos', 'zymase', 'zygote', 'zygose', 'zygoma', 'zygoid', 'zydeco', 'zymes', 'zyme' ] Here is the tmp/scrabble.csv I used. The question is, can a trie be used to find all the words which "contain" some input string, or find all the words which "unscramble" the input string? I am curious how to accomplish this with a Trie. If a trie cannot do this efficiently, then knowing why not, and potentially what I should be looking at instead, will be a great answer as well. From my initial thought-attempts at solving "contains", it seems I would have to create a trie which maps all possible combinations of substrings to the final word, but that seems like it will be an explosion of memory, so not sure how to better reason about this. For "unscrambles", where you put in "caldku" and it finds "duck", amongst other possible words, I think possibly, similar to the linked answer to the other question, maybe sorting "duck" into "cdku", and then storing that in the trie, and then sorting the input to "acdklu", and then searching for "contains" using the previous algorithm, but hmm, no that will break in a few cases. So maybe a trie is not the right approach for these two problems? If it is, roughly how would you do it (you don't need to provide a full implementation, unless you'd like and it's straightforward enough).
Here is an answer to unscrambles that ALSO handles pagination. It actually returns [words, startOfNextPage]. So to find the next page you call it starting at startOfNextPage. The idea is to normalize words by sorting the letters, and then storing the word in the trie once. When searching we can dig into the tree both for the next letter we want, and any letter before it (because the letter we want may come after). So we also store a lookup to know what letters might be found, so that we can break out early without having to look at a lot of bad options. And, of course, we include counts so that we can calculate how much of the trie we have explored and/or skipped over. class Trie { constructor(depth=0) { this.depth = depth; this.children = {}; this.words = []; this.count = 0; this.isSorted = false; this.hasChildWith = {}; } insert (word) { if (word != undefined) { this._insert(Array.from(word).sort(), word); } } _insert (key, word) { this.count++; this.isSorted = false; if (key.length == this.depth) { this.words.push(word); } else { for (let i = this.depth+1; i < key.length; i++) { this.hasChildWith[key[i]] = true; } if (! this.children[key[this.depth]] ) { this.children[key[this.depth]] = new Trie(this.depth+1); } this.children[key[this.depth]]._insert(key, word); } } sort () { if (! this.isSorted) { this.words.sort(); let letters = Object.keys(this.children); letters.sort(); // Keys come out of a hash in insertion order. let orderedChildren = {}; for (let i = 0; i < letters.length; i++) { orderedChildren[letters[i]] = this.children[letters[i]]; } this.children = orderedChildren; } } find (letters, startAt=0, maxCount=null) { return this._find(Array.from(letters).sort(), 0, startAt, maxCount || this.count, 0); } _find (key, keyPos, startAt, maxCount, curPos) { if (curPos + this.count < startAt) { return [[], curPos + this.count]; } this.sort(); // Make sure we are sorted. let answer = []; if (keyPos < key.length) { // We have not yet found all the letters. // tmpPos will track how much we looked at in detail let tmpPos = curPos; tmpPos += this.words.length; for (const [k, v] of Object.entries(this.children)) { if (k < key[keyPos]) { // The next letter we want can be deeper in the trie? if (v.hasChildWith[key[keyPos]]) { // It is! Let's find it. let result = v._find(key, keyPos, startAt, maxCount - answer.length, tmpPos); answer = answer.concat(result[0]); if (maxCount <= answer.length) { // We finished our answer, return it and what we found. return [answer, result[1]]; } } tmpPos += v.count; // Didn't find it, but track that we've seen this. } else if (k == key[keyPos]) { // We found our next letter! Search deeper. let result = v._find(key, keyPos+1, startAt, maxCount - answer.length, tmpPos); answer = answer.concat(result[0]); if (maxCount <= answer.length) { // We finished the search. return [answer, result[1]]; } else { // No other letter can match. break; } } else { // Neither this or any later letter can match. break; } } // Return our partial answer and mark that we went // through this whole node. return [answer, curPos + this.count]; } else { // We have our letters and are recursively finding words. if (startAt <= curPos + this.words.length) { answer = this.words.slice(startAt - curPos); if (maxCount <= answer.length) { // No need to search deeper, we're done. answer = answer.slice(0, maxCount); return [answer, curPos + answer.length]; } curPos += answer.length; } for (const child of Object.values(this.children)) { let result = child._find(key, keyPos, startAt, maxCount - answer.length, curPos); answer = answer.concat(result[0]) if (maxCount <= answer.length) { return [answer, result[1]]; } else { curPos += child.count; } } return [answer, curPos]; } } } exports.Trie = Trie And here is some code to test it with. const fs = require('fs') const AnagramTrie = require('./AnagramTrie') const words = fs.readFileSync('tmp/scrabble.csv', 'utf-8') .trim() .split(/\n+/) .map(x => x.trim()) const trie = new AnagramTrie.Trie() words.forEach(word => trie.insert(word)) console.log(trie.find('b', 0, 12)) console.log(trie.find('b', 0, 6)) console.log(trie.find('b', 11, 6)) console.log(trie.find('zx', 0, 12)) console.log(trie.find('zx', 0, 6)) console.log(trie.find('zx', 60875, 6)) It will return words in the order of their sorted anagram, followed by the word itself. So if you search for admired you'll find unadmired first because the n in un comes before the r in admired. And you'll find that disembarrassed comes before either because it has 2 a's in it.
And here is an answer to contains. Note how, despite using a Trie both times, it needs a lot of customization to the problem we are solving. Sample code to use it is like the other one. You can see the deduplication at work if you search for a. The answer aa (correctly) only comes up once. Also it is a little slower to start up because you have to put words into the data structure multiple times. class Trie { constructor(depth=0, key=[]) { this.depth = depth; this.children = {}; this.words = []; this.count = 0; this.isSorted = false; this.path = key.slice(0, depth).join(""); this.char = key[this.depth-1]; } insert (word) { if (word != undefined) { const key = Array.from(word); for (let i = 0; i < key.length; i++) { this._insert(key.slice(i), word); } } } _insert (key, word) { this.count++; if (this.depth == key.length) { this.words.push(word); } else { if (! this.children[key[this.depth]] ) { this.children[key[this.depth]] = new Trie(this.depth+1, key); } this.children[key[this.depth]]._insert(key, word); } } sort () { if (! this.isSorted) { this.words.sort(); let letters = Object.keys(this.children); letters.sort(); // Keys come out of a hash in insertion order. let orderedChildren = {}; for (let i = 0; i < letters.length; i++) { orderedChildren[letters[i]] = this.children[letters[i]]; } this.children = orderedChildren; this.isSorted } } find (letters, startAt=0, maxCount=null) { // Defaults, special cases, etc. if (this.count <= startAt) { return [[], startAt]; } if (maxCount == null) { maxCount = this.count; } if (letters == "") { // Special case. this.sort(); answer = this.words.slice(startAt, startAt + maxCount); return [answer, startAt + answer.length]; } // We will do the recursive search. const key = Array.from(letters); // The challenge is that each word is stored multiple times. // We want to only find them once. So we will stop searching as soon // as we match our search string twice. // // This requires keeping track of where we are in trying to match our // search string again. And if we fail, backtracking in our attempt // to match. // // Here is the complication. Partial matches can overlap. // // Consider the following search string: // // search: a b a a b a c a b // 0 1 2 3 4 5 6 7 8 // // Now suppose that I'm looking for "c" at 6 next and it isn't an // "c". Well I know I matched "aba" and should next check if I got // character 3, "a". We can encode this logic in an array. // // a b a a b a c a b // backtrackTo: [-1, 0,-1, 1, 0,-1, 3,-1, 0] // // So if I've matched through 5, I check "c", then "a", then "b" // before deciding that I'm not still partway through a match. // // Let's calculate that backtrackTo. We will also calculate a // variable, matchAtAtEnd. Which is how long our longest // running match is at a full match. // We start by assuming that we go back to the beginning. let backtrackTo = [-1]; let rematches = []; let matchAtEnd = 0; for (let i = 1; i < key.length; i++) { if (key[i] == key[0]) { backtrackTo[i] = -1; rematches.push(i); } else { backtrackTo[i] = 0; } } // In our example we have: // // backtrackTo = [-1, 0, -1, -1, 0, -1, 0, -1, 0] // rematches = [2, 3, 5, 7] // // Now let `k` be the length of the current rematch. let k = 1; while (0 < rematches.length) { let nextRematches = []; for (let i = 0; i < rematches.length; i++) { if (i + k == key.length) { matchAtEnd = k-1; } else { if (key[k] == key[i+k]) { nextRematches.push(i); } else { backtrackTo[i+k] = k; } } } rematches = nextRematches; k++; // In our example we get: // // k = 1 // backtrackTo = [-1, 0, -1, -1, 0, -1, 0, -1, 0] // rematches = [2, 3, 5, 7] // matchAtEnd = -1 // // k = 2 // backtrackTo = [-1, 0, -1, 1, 0, -1, 0, -1, 0] // rematches = [3, 7] // matchAtEnd = -1 // // k = 3 // backtrackTo = [-1, 0, -1, 1, 0, -1, 3, -1, 0] // rematches = [] // matchAtEnd = 2 // // and we see that we got the expected backtrackTo AND // we have recorded the fact that at matching // abaabacab we are currently also matching the ab at the // start. // // Now let's find the first match. let node = this; for (let i = 0; i < key.length; i++) { node = node.children[key[i]]; if (!node) { return [[], startAt]; } } return node._find(key, startAt, maxCount, 0, backtrackTo, matchAtEnd) } _find (key, startAt, maxCount, curPos, backtrackTo, nextMatch) { // console.log([key, startAt, maxCount, curPos, backtrackTo, nextMatch, [this.path, this.count]]); // Skip me? if ((curPos + this.count <= startAt) || (key.length <= nextMatch)) { return [[], curPos + this.count]; } this.sort(); let answer = []; if (curPos < startAt) { if (startAt < curPos + this.words.length) { answer = this.words.slice(startAt-curPos, startAt-curPos+maxCount); } else { curPos += this.words.length; // Count the words we are skipping. } } else { answer = this.words.slice(0, maxCount); } curPos += answer.length; if (maxCount <= answer.length) { return [answer, curPos]; } for (const [k, v] of Object.entries(this.children)) { let thisMatch = nextMatch; while ((-1 < thisMatch) && (key[thisMatch] != k)) { thisMatch = backtrackTo[thisMatch]; } thisMatch++; let partialAnswer = null; [partialAnswer, curPos] = v._find(key, startAt, maxCount - answer.length, curPos, backtrackTo, thisMatch); answer = answer.concat(partialAnswer); if (maxCount <= answer.length) { break; // We are done. } } return [answer, curPos]; } } exports.Trie = Trie
How to construct a binary tree from a infix string with brackets?
A non-empty tree is defined as {L,a,R}, L is left subtree, and R is Right subtree. {} for subtree is empty. for example, {{{{},3,{}},2,{{},1,{}}},4,{{{},5,{}},6,{}}} constructs an binary tree like the picture.tree constructed from the string I have found a question for constructs an binary tree from a prefix expression with brackets, but I still have no idea for how to doing this.
I did not get a reply on which data structure or language you expect to use, but here is an implementation of a recursive parser in JavaScript. It uses a regular expression to tokenise the input into braces and data. From those tokens it creates instances of a typical Node class. Finally it outputs that structured tree in a simple, rotated view: class Node { constructor(left, value, right) { this.left = left; this.value = value; this.right = right; } toString() { return (this.right ? this.right.toString().replace(/^/gm, " ") + "\n" : "") + this.value + (this.left ? "\n" + this.left.toString().replace(/^/gm, " ") : ""); } } function createTree(s) { const tokens = s.matchAll(/,([^{},]+),|[{}]|(.)/g); function getToken(expect) { let [all, value, error] = tokens.next().value; value ||= all; if (error || expect && !expect.includes(all)) throw "Unexpected '" + all + "'"; return value; } function dfs(readOpening) { if (readOpening) getToken("{"); if (getToken("{}") == "}") return null; const node = new Node(dfs(), getToken(), dfs(true)); getToken("}"); return node; } return dfs(true); } // Demo const s = "{{{{},3,{}},2,{{},1,{}}},4,{{{},5,{}},6,{}}}"; const root = createTree(s); console.log(root.toString()); // rotated view, with root at the left
Thanks for answerign my question. I finally came up with an naive method by myself. I used recursive function to deal with token and create nodes. It used a counter to judge whether brackets is closed. Here is my code in C++. createTree(string inp){ int leftBracket = 0,rightBracket = 0; if (inp.length() <= 2) { return nullptr; } else { for (int i = 1;;i++) { if (leftBracket == rightBracket && inp[i] >= '0' && inp[i] <= '9') { treeNode* newNode = new treeNode(inp[i]-'0', createTree(inp.substr(1, i - 2)), createTree(inp.substr(i + 2, inp.length() - i - 3))); nodeCounter++; return newNode; } else { if (inp[i] == '{') { leftBracket++; } else if (inp[i] == '}') { rightBracket++; } } } } }
Why is my Singlton constant not staying constant [duplicate]
I have an object x. I'd like to copy it as object y, such that changes to y do not modify x. I realized that copying objects derived from built-in JavaScript objects will result in extra, unwanted properties. This isn't a problem, since I'm copying one of my own literal-constructed objects. How do I correctly clone a JavaScript object?
2022 update There's a new JS standard called structured cloning. It works in many browsers (see Can I Use). const clone = structuredClone(object); Old answer To do this for any object in JavaScript will not be simple or straightforward. You will run into the problem of erroneously picking up attributes from the object's prototype that should be left in the prototype and not copied to the new instance. If, for instance, you are adding a clone method to Object.prototype, as some answers depict, you will need to explicitly skip that attribute. But what if there are other additional methods added to Object.prototype, or other intermediate prototypes, that you don't know about? In that case, you will copy attributes you shouldn't, so you need to detect unforeseen, non-local attributes with the hasOwnProperty method. In addition to non-enumerable attributes, you'll encounter a tougher problem when you try to copy objects that have hidden properties. For example, prototype is a hidden property of a function. Also, an object's prototype is referenced with the attribute __proto__, which is also hidden, and will not be copied by a for/in loop iterating over the source object's attributes. I think __proto__ might be specific to Firefox's JavaScript interpreter and it may be something different in other browsers, but you get the picture. Not everything is enumerable. You can copy a hidden attribute if you know its name, but I don't know of any way to discover it automatically. Yet another snag in the quest for an elegant solution is the problem of setting up the prototype inheritance correctly. If your source object's prototype is Object, then simply creating a new general object with {} will work, but if the source's prototype is some descendant of Object, then you are going to be missing the additional members from that prototype which you skipped using the hasOwnProperty filter, or which were in the prototype, but weren't enumerable in the first place. One solution might be to call the source object's constructor property to get the initial copy object and then copy over the attributes, but then you still will not get non-enumerable attributes. For example, a Date object stores its data as a hidden member: function clone(obj) { if (null == obj || "object" != typeof obj) return obj; var copy = obj.constructor(); for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; } return copy; } var d1 = new Date(); /* Executes function after 5 seconds. */ setTimeout(function(){ var d2 = clone(d1); alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString()); }, 5000); The date string for d1 will be 5 seconds behind that of d2. A way to make one Date the same as another is by calling the setTime method, but that is specific to the Date class. I don't think there is a bullet-proof general solution to this problem, though I would be happy to be wrong! When I had to implement general deep copying I ended up compromising by assuming that I would only need to copy a plain Object, Array, Date, String, Number, or Boolean. The last 3 types are immutable, so I could perform a shallow copy and not worry about it changing. I further assumed that any elements contained in Object or Array would also be one of the 6 simple types in that list. This can be accomplished with code like the following: function clone(obj) { var 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 (var i = 0, len = obj.length; i < len; i++) { copy[i] = clone(obj[i]); } 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! Its type isn't supported."); } The above function will work adequately for the 6 simple types I mentioned, as long as the data in the objects and arrays form a tree structure. That is, there isn't more than one reference to the same data in the object. For example: // This would be cloneable: var tree = { "left" : { "left" : null, "right" : null, "data" : 3 }, "right" : null, "data" : 8 }; // This would kind-of work, but you would get 2 copies of the // inner node instead of 2 references to the same copy var directedAcylicGraph = { "left" : { "left" : null, "right" : null, "data" : 3 }, "data" : 8 }; directedAcyclicGraph["right"] = directedAcyclicGraph["left"]; // Cloning this would cause a stack overflow due to infinite recursion: var cyclicGraph = { "left" : { "left" : null, "right" : null, "data" : 3 }, "data" : 8 }; cyclicGraph["right"] = cyclicGraph; It will not be able to handle any JavaScript object, but it may be sufficient for many purposes as long as you don't assume that it will just work for anything you throw at it.
If you do not use Dates, functions, undefined, regExp or Infinity within your object, a very simple one liner 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' } 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() This works for all kind of objects containing objects, arrays, strings, booleans and numbers. See also this article about the structured clone algorithm of browsers which is used when posting messages to and from a worker. It also contains a function for deep cloning.
In ECMAScript 6 there is Object.assign method, which copies values of all enumerable own properties from one object to another. For example: var x = {myProp: "value"}; var y = Object.assign({}, x); But be aware this is a shallow copy - nested objects are still copied as reference.
With jQuery, you can shallow copy with extend: var copiedObject = jQuery.extend({}, originalObject) subsequent changes to the copiedObject will not affect the originalObject, and vice versa. Or to make a deep copy: var copiedObject = jQuery.extend(true, {}, originalObject)
Per MDN: If you want shallow copy, use Object.assign({}, a) For "deep" copy, use JSON.parse(JSON.stringify(a)) There is no need for external libraries but you need to check browser compatibility first.
An elegant way to clone a Javascript object in one line of code An Object.assign method is part of the ECMAScript 2015 (ES6) standard and does exactly what you need. var clone = Object.assign({}, obj); The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. Read more... The polyfill to support older browsers: if (!Object.assign) { Object.defineProperty(Object, 'assign', { enumerable: false, configurable: true, writable: true, value: function(target) { 'use strict'; if (target === undefined || target === null) { throw new TypeError('Cannot convert first argument to object'); } var to = Object(target); for (var i = 1; i < arguments.length; i++) { var nextSource = arguments[i]; if (nextSource === undefined || nextSource === null) { continue; } nextSource = Object(nextSource); var keysArray = Object.keys(nextSource); for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex]; var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); if (desc !== undefined && desc.enumerable) { to[nextKey] = nextSource[nextKey]; } } } return to; } }); }
There are many answers, but none that mentions Object.create from ECMAScript 5, which admittedly does not give you an exact copy, but sets the source as the prototype of the new object. Thus, this is not an exact answer to the question, but it is a one-line solution and thus elegant. And it works best for 2 cases: Where such inheritance is useful (duh!) Where the source object won't be modified, thus making the relation between the 2 objects a non issue. Example: var foo = { a : 1 }; var bar = Object.create(foo); foo.a; // 1 bar.a; // 1 foo.a = 2; bar.a; // 2 - prototype changed bar.a = 3; foo.a; // Still 2, since setting bar.a makes it an "own" property Why do I consider this solution to be superior? It's native, thus no looping, no recursion. However, older browsers will need a polyfill.
There are several issues with most solutions on the internet. So I decided to make a follow-up, which includes, why the accepted answer shouldn't be accepted. starting situation I want to deep-copy a Javascript Object with all of its children and their children and so on. But since I'm not kind of a normal developer, my Object has normal properties, circular structures and even nested objects. So let's create a circular structure and a nested object first. function Circ() { this.me = this; } function Nested(y) { this.y = y; } Let's bring everything together in an Object named a. var a = { x: 'a', circ: new Circ(), nested: new Nested('a') }; Next, we want to copy a into a variable named b and mutate it. var b = a; b.x = 'b'; b.nested.y = 'b'; You know what happened here because if not you wouldn't even land on this great question. console.log(a, b); a --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } Now let's find a solution. JSON The first attempt I tried was using JSON. var b = JSON.parse( JSON.stringify( a ) ); b.x = 'b'; b.nested.y = 'b'; Don't waste too much time on it, you'll get TypeError: Converting circular structure to JSON. Recursive copy (the accepted "answer") Let's have a look at the accepted answer. function cloneSO(obj) { // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = cloneSO(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { var copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } Looks good, heh? It's a recursive copy of the object and handles other types as well, like Date, but that wasn't a requirement. var b = cloneSO(a); b.x = 'b'; b.nested.y = 'b'; Recursion and circular structures doesn't work well together... RangeError: Maximum call stack size exceeded native solution After arguing with my co-worker, my boss asked us what happened, and he found a simple solution after some googling. It's called Object.create. var b = Object.create(a); b.x = 'b'; b.nested.y = 'b'; This solution was added to Javascript some time ago and even handles circular structure. console.log(a, b); a --> Object { x: "a", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } ... and you see, it didn't work with the nested structure inside. polyfill for the native solution There's a polyfill for Object.create in the older browser just like the IE 8. It's something like recommended by Mozilla, and of course, it's not perfect and results in the same problem as the native solution. function F() {}; function clonePF(o) { F.prototype = o; return new F(); } var b = clonePF(a); b.x = 'b'; b.nested.y = 'b'; I've put F outside the scope so we can have a look at what instanceof tells us. console.log(a, b); a --> Object { x: "a", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> F { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } console.log(typeof a, typeof b); a --> object b --> object console.log(a instanceof Object, b instanceof Object); a --> true b --> true console.log(a instanceof F, b instanceof F); a --> false b --> true Same problem as the native solution, but a little bit worse output. the better (but not perfect) solution When digging around, I found a similar question (In Javascript, when performing a deep copy, how do I avoid a cycle, due to a property being "this"?) to this one, but with a way better solution. function cloneDR(o) { const gdcc = "__getDeepCircularCopy__"; if (o !== Object(o)) { return o; // primitive value } var set = gdcc in o, cache = o[gdcc], result; if (set && typeof cache == "function") { return cache(); } // else o[gdcc] = function() { return result; }; // overwrite if (o instanceof Array) { result = []; for (var i=0; i<o.length; i++) { result[i] = cloneDR(o[i]); } } else { result = {}; for (var prop in o) if (prop != gdcc) result[prop] = cloneDR(o[prop]); else if (set) result[prop] = cloneDR(cache); } if (set) { o[gdcc] = cache; // reset } else { delete o[gdcc]; // unset again } return result; } var b = cloneDR(a); b.x = 'b'; b.nested.y = 'b'; And let's have a look at the output... console.log(a, b); a --> Object { x: "a", circ: Object { me: Object { ... } }, nested: Object { y: "a" } } b --> Object { x: "b", circ: Object { me: Object { ... } }, nested: Object { y: "b" } } console.log(typeof a, typeof b); a --> object b --> object console.log(a instanceof Object, b instanceof Object); a --> true b --> true console.log(a instanceof F, b instanceof F); a --> false b --> false The requirements are matched, but there are still some smaller issues, including changing the instance of nested and circ to Object. The structure of trees that share a leaf won't be copied, they will become two independent leaves: [Object] [Object] / \ / \ / \ / \ |/_ _\| |/_ _\| [Object] [Object] ===> [Object] [Object] \ / | | \ / | | _\| |/_ \|/ \|/ [Object] [Object] [Object] conclusion The last solution using recursion and a cache, may not be the best, but it's a real deep-copy of the object. It handles simple properties, circular structures and nested object, but it will mess up the instance of them while cloning. jsfiddle
If you're okay with a shallow copy, the underscore.js library has a clone method. y = _.clone(x); or you can extend it like copiedObject = _.extend({},originalObject);
OK, imagine you have this object below and you want to clone it: let obj = {a:1, b:2, c:3}; //ES6 or var obj = {a:1, b:2, c:3}; //ES5 the answer is mainly depeneds on which ECMAscript you using, in ES6+, you can simply use Object.assign to do the clone: let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3}; or using spread operator like this: let cloned = {...obj}; //new {a:1, b:2, c:3}; But if you using ES5, you can use few methods, but the JSON.stringify, just make sure you not using for a big chunk of data to copy, but it could be one line handy way in many cases, something like this: let cloned = JSON.parse(JSON.stringify(obj)); //new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over
Update 06 July 2020 There are three (3) ways to clone objects in JavaScript. As objects in JavaScript are reference values, you can't simply just copy using the =. The ways are: const food = { food: 'apple', drink: 'milk' } // 1. Using the "Spread" // ------------------ { ...food } // 2. Using "Object.assign" // ------------------ Object.assign({}, food) // 3. "JSON" // ------------------ JSON.parse(JSON.stringify(food)) // RESULT: // { food: 'apple', drink: 'milk' } This can be used as a reference summary.
One particularly inelegant solution is to use JSON encoding to make deep copies of objects that do not have member methods. The methodology is to JSON encode your target object, then by decoding it, you get the copy you are looking for. You can decode as many times as you want to make as many copies as you need. Of course, functions do not belong in JSON, so this only works for objects without member methods. This methodology was perfect for my use case, since I'm storing JSON blobs in a key-value store, and when they are exposed as objects in a JavaScript API, each object actually contains a copy of the original state of the object so we can calculate the delta after the caller has mutated the exposed object. var object1 = {key:"value"}; var object2 = object1; object2 = JSON.stringify(object1); object2 = JSON.parse(object2); object2.key = "a change"; console.log(object1);// returns value
You can simply use a spread property to copy an object without references. But be careful (see comments), the 'copy' is just on the lowest object/array level. Nested properties are still references! Complete clone: let x = {a: 'value1'} let x2 = {...x} // => mutate without references: x2.a = 'value2' console.log(x.a) // => 'value1' Clone with references on second level: const y = {a: {b: 'value3'}} const y2 = {...y} // => nested object is still a references: y2.a.b = 'value4' console.log(y.a.b) // => 'value4' JavaScript actually does not support deep clones natively. Use an utility function. For example Ramda: http://ramdajs.com/docs/#clone
const objClone = { ...obj }; Be aware that nested objects are still copied as a reference.
From this article: How to copy arrays and objects in Javascript by Brian Huisman: Object.prototype.clone = function() { var newObj = (this instanceof Array) ? [] : {}; for (var i in this) { if (i == 'clone') continue; if (this[i] && typeof this[i] == "object") { newObj[i] = this[i].clone(); } else newObj[i] = this[i] } return newObj; };
For those using AngularJS, there is also direct method for cloning or extending of the objects in this library. var destination = angular.copy(source); or angular.copy(source, destination); More in angular.copy documentation...
function clone(obj) { if(obj == null || typeof(obj) != 'object') return obj; var temp = new obj.constructor(); for(var key in obj) temp[key] = clone(obj[key]); return temp; }
A.Levy's answer is almost complete, here is my little contribution: there is a way how to handle recursive references, see this line if(this[attr]==this) copy[attr] = copy; If the object is XML DOM element, we must use cloneNode instead if(this.cloneNode) return this.cloneNode(true); Inspired by A.Levy's exhaustive study and Calvin's prototyping approach, I offer this solution: Object.prototype.clone = function() { if(this.cloneNode) return this.cloneNode(true); var copy = this instanceof Array ? [] : {}; for(var attr in this) { if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone) copy[attr] = this[attr]; else if(this[attr]==this) copy[attr] = copy; else copy[attr] = this[attr].clone(); } return copy; } Date.prototype.clone = function() { var copy = new Date(); copy.setTime(this.getTime()); return copy; } Number.prototype.clone = Boolean.prototype.clone = String.prototype.clone = function() { return this; } See also Andy Burke's note in the answers.
Performance Today 2020.04.30 I perform tests of chosen solutions on Chrome v81.0, Safari v13.1 and Firefox v75.0 on MacOs High Sierra v10.13.6. I focus on speed of copy DATA (object with simple type fields, not methods etc.). The solutions A-I can make only shallow copy, solutions J-U can make deep copy. Results for shallow copy solution {...obj} (A) is fastest on chrome and firefox and medium fast on safari solution based on Object.assign (B) is fast on all browsers jQuery (E) and lodash (F,G,H) solutions are medium/quite fast solution JSON.parse/stringify (K) is quite slow solutions D and U are slow on all browsers Results for deep copy solution Q is fastest on all browsers jQuery (L) and lodash (J) are medium fast solution JSON.parse/stringify (K) is quite slow solution U is slowest on all browsers lodash (J) and solution U crash on Chrome for 1000 level deep object Details For choosen solutions: A B C(my) D E F G H I J K L M N O P Q R S T U, I perform 4 tests shallow-small: object with 10 non-nested fields - you can run it HERE shallow-big: object with 1000 non-nested fields - you can run it HERE deep-small: object with 10 levels-nested fields - you can run it HERE deep-big: object with 1000 levels-nested fields - you can run it HERE Objects used in tests are show in below snippet let obj_ShallowSmall = { field0: false, field1: true, field2: 1, field3: 0, field4: null, field5: [], field6: {}, field7: "text7", field8: "text8", } let obj_DeepSmall = { level0: { level1: { level2: { level3: { level4: { level5: { level6: { level7: { level8: { level9: [[[[[[[[[['abc']]]]]]]]]], }}}}}}}}}, }; let obj_ShallowBig = Array(1000).fill(0).reduce((a,c,i) => (a['field'+i]=getField(i),a) ,{}); let obj_DeepBig = genDeepObject(1000); // ------------------ // Show objects // ------------------ console.log('obj_ShallowSmall:',JSON.stringify(obj_ShallowSmall)); console.log('obj_DeepSmall:',JSON.stringify(obj_DeepSmall)); console.log('obj_ShallowBig:',JSON.stringify(obj_ShallowBig)); console.log('obj_DeepBig:',JSON.stringify(obj_DeepBig)); // ------------------ // HELPERS // ------------------ function getField(k) { let i=k%10; if(i==0) return false; if(i==1) return true; if(i==2) return k; if(i==3) return 0; if(i==4) return null; if(i==5) return []; if(i==6) return {}; if(i>=7) return "text"+k; } function genDeepObject(N) { // generate: {level0:{level1:{...levelN: {end:[[[...N-times...['abc']...]]] }}}...}}} let obj={}; let o=obj; let arr = []; let a=arr; for(let i=0; i<N; i++) { o['level'+i]={}; o=o['level'+i]; let aa=[]; a.push(aa); a=aa; } a[0]='abc'; o['end']=arr; return obj; } Below snippet presents tested solutions and shows differences between them function A(obj) { return {...obj} } function B(obj) { return Object.assign({}, obj); } function C(obj) { return Object.keys(obj).reduce( (a,c) => (a[c]=obj[c], a), {}) } function D(obj) { let copyOfObject = {}; Object.defineProperties(copyOfObject, Object.getOwnPropertyDescriptors(obj)); return copyOfObject; } function E(obj) { return jQuery.extend({}, obj) // shallow } function F(obj) { return _.clone(obj); } function G(obj) { return _.clone(obj,true); } function H(obj) { return _.extend({},obj); } function I(obj) { if (null == obj || "object" != typeof obj) return obj; var copy = obj.constructor(); for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; } return copy; } function J(obj) { return _.cloneDeep(obj,true); } function K(obj) { return JSON.parse(JSON.stringify(obj)); } function L(obj) { return jQuery.extend(true, {}, obj) // deep } function M(obj) { if(obj == null || typeof(obj) != 'object') return obj; var temp = new obj.constructor(); for(var key in obj) temp[key] = M(obj[key]); return temp; } function N(obj) { let EClone = function(obj) { var newObj = (obj instanceof Array) ? [] : {}; for (var i in obj) { if (i == 'EClone') continue; if (obj[i] && typeof obj[i] == "object") { newObj[i] = EClone(obj[i]); } else newObj[i] = obj[i] } return newObj; }; return EClone(obj); }; function O(obj) { if (obj == null || typeof obj != "object") return obj; if (obj.constructor != Object && obj.constructor != Array) return obj; if (obj.constructor == Date || obj.constructor == RegExp || obj.constructor == Function || obj.constructor == String || obj.constructor == Number || obj.constructor == Boolean) return new obj.constructor(obj); let to = new obj.constructor(); for (var name in obj) { to[name] = typeof to[name] == "undefined" ? O(obj[name], null) : to[name]; } return to; } function P(obj) { function clone(target, source){ for(let key in source){ // Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter. let descriptor = Object.getOwnPropertyDescriptor(source, key); if(descriptor.value instanceof String){ target[key] = new String(descriptor.value); } else if(descriptor.value instanceof Array){ target[key] = clone([], descriptor.value); } else if(descriptor.value instanceof Object){ let prototype = Reflect.getPrototypeOf(descriptor.value); let cloneObject = clone({}, descriptor.value); Reflect.setPrototypeOf(cloneObject, prototype); target[key] = cloneObject; } else { Object.defineProperty(target, key, descriptor); } } let prototype = Reflect.getPrototypeOf(source); Reflect.setPrototypeOf(target, prototype); return target; } return clone({},obj); } function Q(obj) { var 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 (var i = 0, len = obj.length; i < len; i++) { copy[i] = Q(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = Q(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } function R(obj) { const gdcc = "__getDeepCircularCopy__"; if (obj !== Object(obj)) { return obj; // primitive value } var set = gdcc in obj, cache = obj[gdcc], result; if (set && typeof cache == "function") { return cache(); } // else obj[gdcc] = function() { return result; }; // overwrite if (obj instanceof Array) { result = []; for (var i=0; i<obj.length; i++) { result[i] = R(obj[i]); } } else { result = {}; for (var prop in obj) if (prop != gdcc) result[prop] = R(obj[prop]); else if (set) result[prop] = R(cache); } if (set) { obj[gdcc] = cache; // reset } else { delete obj[gdcc]; // unset again } return result; } function S(obj) { const cache = new WeakMap(); // Map of old - new references function copy(object) { if (typeof object !== 'object' || object === null || object instanceof HTMLElement ) return object; // primitive value or HTMLElement if (object instanceof Date) return new Date().setTime(object.getTime()); if (object instanceof RegExp) return new RegExp(object.source, object.flags); if (cache.has(object)) return cache.get(object); const result = object instanceof Array ? [] : {}; cache.set(object, result); // store reference to object before the recursive starts if (object instanceof Array) { for(const o of object) { result.push(copy(o)); } return result; } const keys = Object.keys(object); for (const key of keys) result[key] = copy(object[key]); return result; } return copy(obj); } function T(obj){ var clonedObjectsArray = []; var originalObjectsArray = []; //used to remove the unique ids when finished var next_objid = 0; function objectId(obj) { if (obj == null) return null; if (obj.__obj_id == undefined){ obj.__obj_id = next_objid++; originalObjectsArray[obj.__obj_id] = obj; } return obj.__obj_id; } function cloneRecursive(obj) { if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0; i < obj.length; ++i) { copy[i] = cloneRecursive(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { if (clonedObjectsArray[objectId(obj)] != undefined) return clonedObjectsArray[objectId(obj)]; var copy; if (obj instanceof Function)//Handle Function copy = function(){return obj.apply(this, arguments);}; else copy = {}; clonedObjectsArray[objectId(obj)] = copy; for (var attr in obj) if (attr != "__obj_id" && obj.hasOwnProperty(attr)) copy[attr] = cloneRecursive(obj[attr]); return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } var cloneObj = cloneRecursive(obj); //remove the unique ids for (var i = 0; i < originalObjectsArray.length; i++) { delete originalObjectsArray[i].__obj_id; }; return cloneObj; } function U(obj) { /* Deep copy objects by value rather than by reference, exception: `Proxy` */ const seen = new WeakMap() return clone(obj) function defineProp(object, key, descriptor = {}, copyFrom = {}) { const { configurable: _configurable, writable: _writable } = Object.getOwnPropertyDescriptor(object, key) || { configurable: true, writable: true } const test = _configurable // Can redefine property && (_writable === undefined || _writable) // Can assign to property if (!test || arguments.length <= 2) return test const basisDesc = Object.getOwnPropertyDescriptor(copyFrom, key) || { configurable: true, writable: true } // Custom… || {}; // …or left to native default settings ["get", "set", "value", "writable", "enumerable", "configurable"] .forEach(attr => descriptor[attr] === undefined && (descriptor[attr] = basisDesc[attr]) ) const { get, set, value, writable, enumerable, configurable } = descriptor return Object.defineProperty(object, key, { enumerable, configurable, ...get || set ? { get, set } // Accessor descriptor : { value, writable } // Data descriptor }) } function clone(object) { if (object !== Object(object)) return object /* —— Check if the object belongs to a primitive data type */ if (object instanceof Node) return object.cloneNode(true) /* —— Clone DOM trees */ let _object // The clone of object switch (object.constructor) { case Array: case Object: _object = cloneObject(object) break case Date: _object = new Date(+object) break case Function: const fnStr = String(object) _object = new Function("return " + (/^(?!function |[^{]+?=>)[^(]+?\(/.test(fnStr) ? "function " : "" ) + fnStr )() copyPropDescs(_object, object) break case RegExp: _object = new RegExp(object) break default: switch (Object.prototype.toString.call(object.constructor)) { // // Stem from: case "[object Function]": // `class` case "[object Undefined]": // `Object.create(null)` _object = cloneObject(object) break default: // `Proxy` _object = object } } return _object } function cloneObject(object) { if (seen.has(object)) return seen.get(object) /* —— Handle recursive references (circular structures) */ const _object = Array.isArray(object) ? [] : Object.create(Object.getPrototypeOf(object)) /* —— Assign [[Prototype]] for inheritance */ seen.set(object, _object) /* —— Make `_object` the associative mirror of `object` */ Reflect.ownKeys(object).forEach(key => defineProp(_object, key, { value: clone(object[key]) }, object) ) return _object } function copyPropDescs(target, source) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source) ) } } // ------------------------ // Test properties // ------------------------ console.log(` shallow deep func circ undefined date RegExp bigInt`) log(A); log(B); log(C); log(D); log(E); log(F); log(G); log(H); log(I); log(J); log(K); log(L); log(M); log(N); log(O); log(P); log(Q); log(R); log(S); log(T); log(U); console.log(` shallow deep func circ undefined date RegExp bigInt ---- LEGEND: shallow - solution create shallow copy deep - solution create deep copy func - solution copy functions circ - solution can copy object with circular references undefined - solution copy fields with undefined value date - solution can copy date RegExp - solution can copy fields with regular expressions bigInt - solution can copy BigInt `) // ------------------------ // Helper functions // ------------------------ function deepCompare(obj1,obj2) { return JSON.stringify(obj1)===JSON.stringify(obj2); } function getCase() { // pure data case return { undef: undefined, bool: true, num: 1, str: "txt1", e1: null, e2: [], e3: {}, e4: 0, e5: false, arr: [ false, 2, "txt3", null, [], {}, [ true,4,"txt5",null, [], {}, [true,6,"txt7",null,[],{} ], {bool: true,num: 8, str: "txt9", e1:null, e2:[] ,e3:{} ,e4: 0, e5: false} ], {bool: true,num: 10, str: "txt11", e1:null, e2:[] ,e3:{} ,e4: 0, e5: false} ], obj: { bool: true, num: 12, str: "txt13", e1: null, e2: [], e3: {}, e4: 0, e5: false, arr: [true,14,"txt15",null,[],{} ], obj: { bool: true, num: 16, str: "txt17", e1: null, e2: [], e3: {}, e4: 0, e5: false, arr: [true,18,"txt19",null,[],{} ], obj: {bool: true,num: 20, str: "txt21", e1:null, e2:[] ,e3:{} ,e4: 0, e5: false} } } }; } function check(org, copy, field, newValue) { copy[field] = newValue; return deepCompare(org,copy); } function testFunc(f) { let o = { a:1, fun: (i,j)=> i+j }; let c = f(o); let val = false try{ val = c.fun(3,4)==7; } catch(e) { } return val; } function testCirc(f) { function Circ() { this.me = this; } var o = { x: 'a', circ: new Circ(), obj_circ: null, }; o.obj_circ = o; let val = false; try{ let c = f(o); val = (o.obj_circ == o) && (o.circ == o.circ.me); } catch(e) { } return val; } function testRegExp(f) { let o = { re: /a[0-9]+/, }; let val = false; try{ let c = f(o); val = (String(c.re) == String(/a[0-9]+/)); } catch(e) { } return val; } function testDate(f) { let o = { date: new Date(), }; let val = false; try{ let c = f(o); val = (+new Date(c.date) == +new Date(o.date)); } catch(e) { } return val; } function testBigInt(f) { let val = false; try{ let o = { big: 123n, }; let c = f(o); val = o.big == c.big; } catch(e) { } return val; } function log(f) { let o = getCase(); // orginal object let oB = getCase(); // "backup" used for shallow valid test let c1 = f(o); // copy 1 for reference let c2 = f(o); // copy 2 for test shallow values let c3 = f(o); // copy 3 for test deep values let is_proper_copy = deepCompare(c1,o); // shoud be true // shallow changes let testShallow = [ ['bool',false],['num',666],['str','xyz'],['arr',[]],['obj',{}] ] .reduce((acc,curr)=> acc && check(c1,c2,curr[0], curr[1]), true ); // should be true (original object shoud not have changed shallow fields) let is_valid = deepCompare(o,oB); // deep test (intruduce some change) if (c3.arr[6]) c3.arr[6][7].num = 777; let diff_shallow = !testShallow; // shoud be true (shallow field was copied) let diff_deep = !deepCompare(c1,c3); // shoud be true (deep field was copied) let can_copy_functions = testFunc(f); let can_copy_circular = testCirc(f); let can_copy_regexp = testRegExp(f); let can_copy_date = testDate(f); let can_copy_bigInt = testBigInt(f); let has_undefined = 'undef' in c1; // field with undefined value is copied? let is_ok = is_valid && is_proper_copy; let b=(bool) => (bool+'').padEnd(5,' '); // bool value to formated string testFunc(f); if(is_ok) { console.log(`${f.name} ${b(diff_shallow)} ${b(diff_deep)} ${b(can_copy_functions)} ${b(can_copy_circular)} ${b(has_undefined)} ${b(can_copy_date)} ${b(can_copy_regexp)} ${b(can_copy_bigInt)}`) } else { console.log(`${f.name}: INVALID ${is_valid} ${is_proper_copy}`,{c1}) } } <script src="https://code.jquery.com/jquery-3.5.0.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script> This snippet only presents tested solutions and show differences between them (but it no make performence tests) Below there are example results for Chrome for shallow-big object
Using Lodash: var y = _.clone(x, true);
In ES-6 you can simply use Object.assign(...). Ex: let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); A good reference is here: https://googlechrome.github.io/samples/object-assign-es6/
Interested in cloning simple objects: JSON.parse(JSON.stringify(json_original)); Source : How to copy JavaScript object to new variable NOT by reference?
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj) ES6 solution if you want to (shallow) clone a class instance and not just a property object.
Structured Cloning 2022 update: The structuredClone() global function is already available in Node 17, Deno 1.14, and most major browsers (see Can I Use). You can use the same structured clone mechanism that the HTML standard includes for sending data between realms. const clone = structuredClone(original); See the other answer for more details.
You can clone an object and remove any reference from the previous one using a single line of code. Simply do: var obj1 = { text: 'moo1' }; var obj2 = Object.create(obj1); // Creates a new clone without references obj2.text = 'moo2'; // Only updates obj2's text property console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'} For browsers / engines that do not currently support Object.create you can use this polyfill: // Polyfill Object.create if it does not exist if (!Object.create) { Object.create = function (o) { var F = function () {}; F.prototype = o; return new F(); }; }
New answer to an old question! If you have the pleasure of having using ECMAScript 2016 (ES6) with Spread Syntax, it's easy. keepMeTheSame = {first: "Me!", second: "You!"}; cloned = {...keepMeTheSame} This provides a clean method for a shallow copy of an object. Making a deep copy, meaning makign a new copy of every value in every recursively nested object, requires on of the heavier solutions above. JavaScript keeps evolving.
I think there is a simple and working answer. In deep copying there are two concerns: Keep properties independent to each other. And keep the methods alive on cloned object. So I think one simple solution will be to first serialize and deserialize and then do an assign on it to copy functions too. let deepCloned = JSON.parse(JSON.stringify(source)); let merged = Object.assign({}, source); Object.assign(merged, deepCloned); Although this question has many answers, I hope this one helps too.
For a deep copy and clone, JSON.stringify then JSON.parse the object: obj = { a: 0 , b: { c: 0}}; let deepClone = JSON.parse(JSON.stringify(obj)); obj.a = 5; obj.b.c = 5; console.log(JSON.stringify(deepClone)); // { a: 0, b: { c: 0}}
(The following was mainly an integration of #Maciej Bukowski, #A. Levy, #Jan Turoň, #Redu's answers, and #LeviRoberts, #RobG's comments, many thanks to them!!!) Deep copy? — YES! (mostly); Shallow copy? — NO! (except Proxy). I sincerely welcome everyone to test clone(). In addition, defineProp() is designed to easily and quickly (re)define or copy any type of descriptor. Function function clone(object) { /* Deep copy objects by value rather than by reference, exception: `Proxy` */ const seen = new WeakMap() return clone(object) function clone(object) { if (object !== Object(object)) return object /* —— Check if the object belongs to a primitive data type */ if (object instanceof Node) return object.cloneNode(true) /* —— Clone DOM trees */ let _object // The clone of object switch (object.constructor) { case Array: case Object: _object = cloneObject(object) break case Date: _object = new Date(+object) break case Function: _object = copyFn(object) break case RegExp: _object = new RegExp(object) break default: switch (Object.prototype.toString.call(object.constructor)) { // // Stem from: case "[object Function]": switch (object[Symbol.toStringTag]) { case undefined: _object = cloneObject(object) // `class` break case "AsyncFunction": case "GeneratorFunction": case "AsyncGeneratorFunction": _object = copyFn(object) break default: _object = object } break case "[object Undefined]": // `Object.create(null)` _object = cloneObject(object) break default: _object = object // `Proxy` } } return _object } function cloneObject(object) { if (seen.has(object)) return seen.get(object) /* —— Handle recursive references (circular structures) */ const _object = Array.isArray(object) ? [] : Object.create(Object.getPrototypeOf(object)) /* —— Assign [[Prototype]] for inheritance */ seen.set(object, _object) /* —— Make `_object` the associative mirror of `object` */ Reflect.ownKeys(object).forEach(key => defineProp(_object, key, { value: clone(object[key]) }, object) ) return _object } } function copyPropDescs(target, source) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source) ) } function convertFnToStr(fn) { let fnStr = String(fn) if (fn.name.startsWith("[")) // isSymbolKey fnStr = fnStr.replace(/\[Symbol\..+?\]/, '') fnStr = /^(?!(async )?(function\b|[^{]+?=>))[^(]+?\(/.test(fnStr) ? fnStr.replace(/^(async )?(\*)?/, "$1function$2 ") : fnStr return fnStr } function copyFn(fn) { const newFn = new Function(`return ${convertFnToStr(fn)}`)() copyPropDescs(newFn, fn) return newFn } function defineProp(object, key, descriptor = {}, copyFrom = {}) { const { configurable: _configurable, writable: _writable } = Object.getOwnPropertyDescriptor(object, key) || { configurable: true, writable: true } const test = _configurable // Can redefine property && (_writable === undefined || _writable) // Can assign to property if (!test || arguments.length <= 2) return test const basisDesc = Object.getOwnPropertyDescriptor(copyFrom, key) || { configurable: true, writable: true } // Custom… || {}; // …or left to native default settings ["get", "set", "value", "writable", "enumerable", "configurable"] .forEach(attr => descriptor[attr] === undefined && (descriptor[attr] = basisDesc[attr]) ) const { get, set, value, writable, enumerable, configurable } = descriptor return Object.defineProperty(object, key, { enumerable, configurable, ...get || set ? { get, set } // Accessor descriptor : { value, writable } // Data descriptor }) } // Tests const obj0 = { u: undefined, nul: null, t: true, num: 9, str: "", sym: Symbol("symbol"), [Symbol("e")]: Math.E, arr: [[0], [1, 2]], d: new Date(), re: /f/g, get g() { return 0 }, o: { n: 0, o: { f: function (...args) { } } }, f: { getAccessorStr(object) { return [] .concat(... Object.values(Object.getOwnPropertyDescriptors(object)) .filter(desc => desc.writable === undefined) .map(desc => Object.values(desc)) ) .filter(prop => typeof prop === "function") .map(String) }, f0: function f0() { }, f1: function () { }, f2: a => a / (a + 1), f3: () => 0, f4(params) { return param => param + params }, f5: (a, b) => ({ c = 0 } = {}) => a + b + c } } defineProp(obj0, "s", { set(v) { this._s = v } }) defineProp(obj0.arr, "tint", { value: { is: "non-enumerable" } }) obj0.arr[0].name = "nested array" let obj1 = clone(obj0) obj1.o.n = 1 obj1.o.o.g = function g(a = 0, b = 0) { return a + b } obj1.arr[1][1] = 3 obj1.d.setTime(+obj0.d + 60 * 1000) obj1.arr.tint.is = "enumerable? no" obj1.arr[0].name = "a nested arr" defineProp(obj1, "s", { set(v) { this._s = v + 1 } }) defineProp(obj1.re, "multiline", { value: true }) console.log("\n\n" + "-".repeat(2 ** 6)) console.log(">:>: Test - Routinely") console.log("obj0:\n ", JSON.stringify(obj0)) console.log("obj1:\n ", JSON.stringify(obj1)) console.log() console.log("obj0:\n ", obj0) console.log("obj1:\n ", obj1) console.log() console.log("obj0\n ", ".arr.tint:", obj0.arr.tint, "\n ", ".arr[0].name:", obj0.arr[0].name ) console.log("obj1\n ", ".arr.tint:", obj1.arr.tint, "\n ", ".arr[0].name:", obj1.arr[0].name ) console.log() console.log("Accessor-type descriptor\n ", "of obj0:", obj0.f.getAccessorStr(obj0), "\n ", "of obj1:", obj1.f.getAccessorStr(obj1), "\n ", "set (obj0 & obj1) .s :", obj0.s = obj1.s = 0, "\n ", " → (obj0 , obj1) ._s:", obj0._s, ",", obj1._s ) console.log("—— obj0 has not been interfered.") console.log("\n\n" + "-".repeat(2 ** 6)) console.log(">:>: Test - More kinds of functions") const fnsForTest = { f(_) { return _ }, func: _ => _, aFunc: async _ => _, async function() { }, async asyncFunc() { }, aFn: async function () { }, *gen() { }, async *asyncGen() { }, aG1: async function* () { }, aG2: async function* gen() { }, *[Symbol.iterator]() { yield* Object.keys(this) } } console.log(Reflect.ownKeys(fnsForTest).map(k => `${String(k)}: ${fnsForTest[k].name}--> ${String(fnsForTest[k])}` ).join("\n")) const normedFnsStr = `{ f: function f(_) { return _ }, func: _ => _, aFunc: async _ => _, function: async function() { }, asyncFunc: async function asyncFunc() { }, aFn: async function () { }, gen: function* gen() { }, asyncGen: async function* asyncGen() { }, aG1: async function* () { }, aG2: async function* gen() { }, [Symbol.iterator]: function* () { yield* Object.keys(this) } }` const copiedFnsForTest = clone(fnsForTest) console.log("fnsForTest:", fnsForTest) console.log("fnsForTest (copied):", copiedFnsForTest) console.log("fnsForTest (normed str):", eval(`(${normedFnsStr})`)) console.log("Comparison of fnsForTest and its clone:", Reflect.ownKeys(fnsForTest).map(k => [k, fnsForTest[k] === copiedFnsForTest[k]] ) ) console.log("\n\n" + "-".repeat(2 ** 6)) console.log(">:>: Test - Circular structures") obj0.o.r = {} obj0.o.r.recursion = obj0.o obj0.arr[1] = obj0.arr obj1 = clone(obj0) console.log("obj0:\n ", obj0) console.log("obj1:\n ", obj1) console.log("Clear obj0's recursion:", obj0.o.r.recursion = null, obj0.arr[1] = 1 ) console.log( "obj0\n ", ".o.r:", obj0.o.r, "\n ", ".arr:", obj0.arr ) console.log( "obj1\n ", ".o.r:", obj1.o.r, "\n ", ".arr:", obj1.arr ) console.log("—— obj1 has not been interfered.") console.log("\n\n" + "-".repeat(2 ** 6)) console.log(">:>: Test - Classes") class Person { constructor(name) { this.name = name } } class Boy extends Person { } Boy.prototype.sex = "M" const boy0 = new Boy boy0.hobby = { sport: "spaceflight" } const boy1 = clone(boy0) boy1.hobby.sport = "superluminal flight" boy0.name = "one" boy1.name = "neo" console.log("boy0:\n ", boy0) console.log("boy1:\n ", boy1) console.log("boy1's prototype === boy0's:", Object.getPrototypeOf(boy1) === Object.getPrototypeOf(boy0) ) References Object.create() | MDN Object.defineProperties() | MDN Enumerability and ownership of properties | MDN TypeError: cyclic object value | MDN Language tricks used Conditionally add prop to object
Use lodash _.cloneDeep(). Shallow Copy: lodash _.clone() A shallow copy can be made by simply copying the reference. let obj1 = { a: 0, b: { c: 0, e: { f: 0 } } }; let obj3 = _.clone(obj1); obj1.a = 4; obj1.b.c = 4; obj1.b.e.f = 100; console.log(JSON.stringify(obj1)); //{"a":4,"b":{"c":4,"e":{"f":100}}} console.log(JSON.stringify(obj3)); //{"a":0,"b":{"c":4,"e":{"f":100}}} Deep Copy: lodash _.cloneDeep() fields are dereferenced: rather than references to objects being copied let obj1 = { a: 0, b: { c: 0, e: { f: 0 } } }; let obj3 = _.cloneDeep(obj1); obj1.a = 100; obj1.b.c = 100; obj1.b.e.f = 100; console.log(JSON.stringify(obj1)); {"a":100,"b":{"c":100,"e":{"f":100}}} console.log(JSON.stringify(obj3)); {"a":0,"b":{"c":0,"e":{"f":0}}}
I would like my bot to delete the message that contains a keyword or that contains similar characters
in my bot I have implemented a keyword filter that the bot reviews in each message that is written in the chat, until now it works, but I want to improve it, for reasons of respect I will not put words here, so I will put some others example, The bot detects if you write for example "vulgar", "badword", "hello" But what I want to achieve is to detect if they write "hellooo", "vuulgarr", vulg4rr" This is my base where I have the words stored: badwords.js var words = ["vulgar", "vulg4r", "hello", "badword4", "badword5"] module.exports = words; This is my function that checks if a bad word comes on the way, split any words and then deletes the message if it finds a result, with indexOf() index.js const _ = require('lodash'); const badwords = require('./badwords'); /** * Functions */ // compares every word to badWords array from badWords.js function checkWord(word) { return badwords.indexOf(word) > -1; } /** * Main Module */ module.exports = function (self, nick, channel, message) { 'use strict'; message = message.toLowerCase(); message = message.split(' '); nick = nick; channel = channel.toLowerCase(); for (var i = 0, len = message.length; i < len; i++) { if (checkWord(message[i])) { self.send('.ban', channel, nick); } } } Any idea to improve it?, thank's
A more complicated method We can have two pointers on both strings to compare, but skipping offsets upon duplicates: function checkString(message, keyword) { while(message.length > 0) { if(checkPrefix(message, keyword)) return true message = message.substr(1) } } function checkPrefix(message, keyword) { // keyword is one of the keywords let om = 0, ok = 0 while (true) { if (ok >= keyword.length) return true // we have finished reading keyword, and everything matched if(om >= message.length) return false // message is shorter than keyword while (om + 1 < message.length && message.charAt(om) === message.charAt(om + 1)) om++ // skip consecutive repetitions in message while (ok + 1 < keyword.length && keyword.charAt(ok) === keyword.charAt(ok + 1)) ok++ // skip consecutive repetitions in keyword if (message.charAt(om) !== message.charAt(ok)) return false // encountered an inconsistent character } } A simpler method Just scan the repetitions in a string and delete them first. function removeDuplicates(string) { for (let i = 0; i < string.length - 1; ) { if (string.charAt(i) === string.charAt(i + 1)) { string = string.substr(0, i) + string.substr(i + 1) // skip string[i] } else { i++ // not duplicate, proceed to next pair } } } Then you can compare directly: removeDuplicates(message).indexOf(removeDuplicates(keyword)) !== -1 You can apply it like this: for (const part in message.split(" ")) { for (word in words) { if (removeDuplicates(part).indexOf(removeDuplicates(word)) !== -1) self.send(".ban", ...) break } }
scan string operators - javascript
In a calculator I own 4 input type ="number" in particular: <input type = "number" id ="mol" min="1" max="4"> <input type = "number" id ="div" min="1" max="4"> <input type = "number" id ="add" min="1" max="4"> <input type = "number" id ="min" min="1" max="4"> In a textbox, I insert the mathematical expression for extended. <input type = "text" id = "exp" readonly> The numerical values and the operators have gone through the normal buttons. So, for example, the expression inserted in the textbox is this: 8*5-9/2+3 Now I would want that when I press the equal key, based on the priority that the customer has given to the operands, the expression result changed. multiplication: 1 division: 4 subtraction: 2 addition: 3 -> 40 - 9 / 2 + 3 -> 31 / 2 + 3 -> 31 / 5 -> = 6.2 I think this is very difficult to achieve. Get the value of the textbox and evaluate the result based on the priority of the operands is really extreme. What do you propose?
Try using the split method: http://msdn.microsoft.com/en-us/library/t5az126b(v=vs.94).aspx Split on the operator with the first priority first, then split each group by the second operator, then for each subgroup split by the third operator, and for each of those sub-subgroups split by the fourth. Then apply the operator to the groups moving upward. Conceptual example (not the full code you'll need, but should give an idea): var expression = "8*5-9/2+3"; // Get this from the data var operator1Groups = expression.split("*"); // Instead of hardcoding this, retrieve which operator has highest priority from the data for (var i in operator1Groups) { var operator2Groups = operator1Groups[i].split("+"); // Similarly, don't hardcode the operator // And so on... // Once you get to the lowest operator, start applying the operator to each group }
The way to do this is with an Operator Precedence Parser. They are commonly implemented using Djikstra's Shunting-yard Algorithm. You could specify the precedence by loading the operators and precedences into a list and then running the algorithm: function parse(inputExpression, operators) { // Strip out anything that isn't a number or a math operator var tokens = inputExpression .replace(/[^0-9+\-*\/()]/g, '') .split(/([+\-*\/()])/) .filter(function(x) { return x != ""; }); var outputQ = []; // push = push, pop = pop var operStk = []; // enqueue = push, dequeue = shift function top(stack) { return stack[stack.length-1]; } while(tokens.length !== 0) { var token = tokens.shift(); if(!isNaN(Number(token))) { outputQ.push(token); } else if (operators.hasOwnProperty(token)) { while(operators[token] >= operators[top(operStk)]) outputQ.push(operStk.pop()); operStk.push(token); } else if (token == '(') { operStk.push(token); } else if (token == ')') { while(top(operStk) != '(' && operStk.length != 0) outputQ.push(operStk.pop()); if(operStk.length == 0) return null; operStk.pop(); // Get rid of the l-paren } else { console.log("Bad token '" + token + "'"); return null; } } while(operStk.length > 0) outputQ.push(operStk.pop()); return outputQ; } function evaluate(parseResult) { if (parseResult === null) return null; var valueStack = []; while(parseResult.length !== 0) { var op = parseResult.shift(); if(!isNaN(Number(op))) valueStack.push(Number(op)); else { var val2 = valueStack.pop(); var val1 = valueStack.pop(); if(op == '+') { valueStack.push(val1 + val2); } else if(op == '-') { valueStack.push(val1 - val2); } else if(op == '*') { valueStack.push(val1 * val2); } else if(op == '/') { valueStack.push(val1 / val2); } else { console.log("Invalid operator '" + op + "'"); return null; } } } if(valueStack.length !== 1) { console.log("Invalid stack. Remaining: " + valueStack); return null; } return valueStack.pop(); } Usage: var operators = { "+": 3, "-": 2, "*": 1, "/": 4 }; evaluate(parse("40 - 9 / 2 + 3", operators)); // == 6.2 Note that this will not handle unary minus, because it's difficult to do with Shunting-yard, and because you aren't asking for a precedence for it. On the bright side, it does support parenthesis. Hope this helps! Alex