Javascript Replacement With Object Destructuring - javascript

I have a variable like below:
var temp = 'Hello world {variable1}. It is just a {variable2}';
And I have a object like below:
var object = {variable1: 12, variable2: 15, variable3: 20 ...};
As a result, I want to replace temp data with object variables. temp.replace(object...)
It can be solved by
Object.keys(object).forEach(o => temp.replace(o, object[o]));
Is there a more practical way?

You could take a function for replacement and hand over the key for getting the value.
var temp = 'Hello world {variable1}. It is just a {variable2}',
object = { variable1: 12, variable2: 15, variable3: 20 },
rendered = temp.replace(/\{([^\}]+)\}/g, (_, k) => object[k]);
console.log(rendered);

String.prototype.replace can replace matches with a function. You could replace all {...} with this for example:
temp.replace(/\{([^}]+)\}/g, (_, match) => object[match]);
You might want to match on character classes only, to not allow { with spaces or *strange* things_here! } (but JS could allow any kind of string)

Depending on if your variable temp going to always have a dynamic number of variables and if you are trying to just get all the values in the object.
You can do something like this using destructuring and string literals if you know what exactly is in object
const {variable1, variable2, variable3} = object
var temp = `Hello world ${variable1}. It is just a ${variable2}.`
console.log(temp) \\ "Hello world 12. It is just a 15"

Related

How to convert JavaScript object into LITERAL string?

If I have the object literal:
{a: "hello"}
Is there a Javascript function to convert this object into a literal string, so that the output would be the literal syntax:
'{a: "hello"}'
With JSON.stringify the output would be
'{"a": "hello"}'
You can do it with JSON.stringify and then with String.replace like follows:
var jsObj =
{
abc: "hello",
bca: "allo",
cab: "dd:cc",
d: ["hello", "llo", "dd:cc"],
e: {abc: "hello", bca: "allo", cab: "dd:cc"}
};
function format(obj)
{
var str = JSON.stringify(obj, 0, 4),
arr = str.match(/".*?":/g);
for(var i = 0; i < arr.length; i++)
str = str.replace(arr[i], arr[i].replace(/"/g,''));
return str;
}
console.log(format(jsObj));
JavaScript has no built-in functions that will convert an object to a string representation of it which either:
Uses identifiers instead of strings for property names
Represents the original syntax used to create the object
You could write your own function for the former (at least when the property name can be represented as a literal) but the latter is impossible as JavaScript stores no information about the source code used to create the object in the first place.
Ok just for fun...roll your own?
const stringify = (obj) => {
// Iterate over keys, reducing to a string
let str = Object.keys(obj).reduce((acc, cur) => {
let next = `${cur}: "${obj[cur]}"`;
return acc
? `${acc}, ${next}`
: `{${next}`;
}, '');
// Return, appending final '}'
return `${str}}`;
}
document.write(stringify({
foo:1,
bar:'seat'
}));
That said, your exact requirements aren't clear so I'm not sure this will meet them. But it might be a starting point if there's no native solution that works.
It does convert it to the literal syntax. You are able to create objects with multiple forms of syntax. Both of the following object declarations are valid:
var a = {a: "a"}
var b = {"b": "b"}
If you want to remove the "" around the key you should be able to match them with the following regex /\"(.*?)\":/g and replace them with something like this:
function reformat(str) {
var myRegexp = /\"(.*?)\":/g;
match = myRegexp.exec(str);
while (match != null) {
str = str.replace(match[0], match[1] + ":");
match = myRegexp.exec(str);
}
return str;
}
Hope that helps :)

What does map(Number) do here?

var strArr = ["[1,2,3,4]","[1,2,3,4"]];
var arr1 = strArr[0].match(/\d+/g).map(Number);
I know that the map() method creates a new array with the results of calling a provided function on every element in the calling array. Here as Number is a wrapper object I am not able to understand what's going on.
What I understood is that if I console log removing the map method I get an array of strings whereas including the map method I get an array of numbers.I would like to know how map is able to take each string and converting to number.
var arr1 = strArr[0].match(/\d+/g).map(Number);
is equivalent to
var arr1 = strArr[0].match(/\d+/g).map((str, ind, arr) => Number(str, ind, arr));
The reason Number works despite passing extra arguments in is because it ignores everything but the first argument. You cannot expect every function to behave accordingly, since not all functions ignore everything but the first argument, but in this case it is a convenient shortcut. Another neat example that works well is converting truthy and falsy values to booleans:
var arrBool = arrAny.map(Boolean);
strArr[0] //selects the first string. "[1,2,3,4]"
.match(/\d+/g) // give an array of all continuos strings of digits. ['1','2','3','4']
.map(Number) // Calls Number on each value in the array (casting it to a number)
// and returns the array of results. [1,2,3,4]
//
// Keep in mind Number(val) attempts to create a Number from
// what ever is passed to it. If it is a string itll
// try to convert the string to a numerical value.
Its a complicated way of parsing a string containing an array literal. Seems like a complicated way of doing:
JSON.parse(strArr[0])
but without more context I cant tell you if its bad programming or if there is a good reason for it.
Actually Number is a function, and it can easily be proved:
typeof Number === 'function'; // true
Hence it can be used in any case where functions are expected (and naturally it can be passed as an argument):
Number("5") === 5; // true
let arr = ["442", "452h", "424", "foo", "bar", "31", "35"];
arr = arr.filter(x => !isNaN(Number(x))); // ["442", "424", "31", "35"]
And finally:
const arr2 = arr.map(x => Number(x)); // [442, 424, 31, 35]
const arr3 = arr.map(Number); // [442, 424, 31, 35] – the same result
UPD: To make it look extra-easy, let us compose a simple function that does exactly the same thing as the inbuilt Number function (converts values of other types to the number type):
const toNumber = x => +x;
// OR: function toNumber(x) { return +x; }
const arr4 = arr.map(toNumber); // also [442, 424, 31, 35]
You are passing in the Number object/function and converting a single thing that matches that regex in strArr into a Number
It's the same as doing Number(x), where x is an index in the array.
For example,
var num1 = "1";
var num2 = "2";
var result = Number(num1) + Number(num2); // This will work since they are both numbers now.
So calling map on the strings in the array just converts them that specific index into a Number object.
Learn more about Numbers here.

JS Variable pulling other variables into it

I know the heading of this questions seems vague - but it's because I simply don't know how to summarize it appropriately.
I'm working on a project where I enter some text, and it's translated into something else.
There's a fiddle here.
If I enter 4, it translates to the word for.
If I enter b4, it should translate to before.
Instead, it translates to bfor, because it's capturing the variable 4 as a separate variable.
I've tried changing the order, but it doesn't work. Is this a regex problem?
My variables are identified in the JS.
var replaceValues = {
'4' : 'for',
'b4' : 'before'
}
$('.bs-text').keyup(function (event) {
newText = event.target.value;
for (var txt in replaceValues) {
var temp = new RegExp(txt, 'gim');
newText = newText.replace(temp, replaceValues[txt]);
}
$('.human-text').text(newText);
});
As I noted in the comments, JS objects does not have defined order of its keys, so it is not a good idea to count on this when you know the dictionary will get much bigger.
More about this in another SO question: Does JavaScript Guarantee Object Property Order?
Instead, use simple array that will have the order you define. Sorting of this dictionary array can be done in JS too, you do not need to handle this by your own.
var replaceValues = [
{key: '4', value: 'for'},
{key: 'b4', value: 'before'},
];
// sort the values so longer keys go first
replaceValues.sort((a, b) => b.key.length - a.key.length);
$('.bs-text').keyup(function (event) {
var newText = event.target.value;
for (var txt in replaceValues) {
var replacement = replaceValues[txt];
var temp = new RegExp(replacement.key, 'gim');
newText = newText.replace(temp, replacement.value);
}
$('.human-text').text(newText);
});
You could also use ES6 Map, it should have order guarantied. But be aware that it is not enough to create Map from Object:
A Map object iterates its elements in insertion order — a for...of loop returns an array of [key, value] for each iteration.
It should be noted that a Map which is a map of an object, especially a dictionary of dictionaries, will only map to the object's insertion order—which is random and not ordered.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Objects_and_maps_compared
As mentioned in the comments, you have to look for the longest match first. One option is to generate a single regular expression from the search words, ordered by length, and use a callback to get the correct replacement value.
var replaceValues = {
'4': 'for',
'b4': 'before'
};
// generates something equivalent to `/b4|4/gmi`
var pattern = new RegExp(
Object.keys(replaceValues)
.sort((a, b) => b.length - a.length)
.join('|'),
'gmi'
);
var newText = '4 me b4 me';
console.log(newText.replace(pattern, match => replaceValues[match]));
This works because the regex engine matches alternatives from left to right (i.e. if b4 matches it won't try to match 4). Not sure how this solution scales with more searchwords, but it might actually better because you are only matching the string once instead of n times, i.e. the regex engine doesn't have to traverse the whole string multiple times.
The object property has ":" character within property value
$('.bs-text').keyup(function (event) {
var newText = event.target.value;
if (replaceValues[newText]) {
$('.human-text').text(replaceValues[newText])
};
});
jsfiddle http://jsfiddle.net/je89deam/5/

How to extract value from an Array in Javascript

I am querying my db in node and have got the result in the form of an object like this - [ [1234] ].
I want to extract this value and convert it into a string and then pass it onto the client side. I have written the other required code but I am not able to get value from this object. Can anyone help me in getting the value and converting it to string?
Since, the result you've got is a two-dimensional array, you can get the value and convert it into a string (using toString() method) in the following way ...
var result = [ [1234] ];
var string;
result.forEach(function(e) {
string = e.toString();
});
console.log(string);
** this solution will also work if you have multiple results, ie. [ [1234], [5678] ]
You have a nested array, meaning that you have an array inside another array:
[ [1234] ]
// ^-^====^-^
To get the first value of the parent array, use the square brackets: [0]. Remember that indexes start at 0!
If you have val = [[1234]], val[0] gets the enclosed array: [1234]. Then, 1234 is a value in that array (the first value), so you use the square brackets again to get it: val[0][0].
To convert to string, you can use + "" which forces the number to become a string, or the toString() method.
var val = [[1234]];
var str = val[0][0] + "";
// or val[0][0].toString();
console.log(str, typeof str);
You can read more about arrays here.
var response = [ [1234] ];
console.log(response[0][0]);
to extract values from a string array or an array we can use .toString()
Ex:
let names = ["peter","joe","harry"];
let fname = names.toString();
output = peter ,joe,harry
or
let name:string[] = this.customerContacts.map(
res => res.firstname
let fname =name.toString();
Using De-structuring Array concept:
const arr = [[1, 2, 3, 4, 5]];
const [[p, q, r, s, t]] = arr;
console.log(p, q, r, s, t);
Output: 1 2 3 4 5

How to dynamically set the key in a reduce function

I have a .txt file with all the scrabble letter quantities in:
A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1
I am trying to get an array of objects from this, where the key is the letter, and the value is the number.
The problem I am having is where I am trying to set the key to be the first item in the array (that I split earlier) [A, 9].
The code I have is as follows. Any tips would be gratefully received :)
import fs from 'fs'
var output = fs.readFileSync('scrabble-quantities.txt', 'utf-8')
.trim()
.split(', ')
.map(item => item.split('-'))
.reduce((quantities, item) => {
quantities.push({
item[0]: item[1]
})
return quantities
}, [])
Thanks
I would use an object instead of an array. It's easier and more natural how JS works:
// ...
.reduce((quantities, item) => {
quantities[item[0]] = item[1];
return quantities;
}, {});
The resulting output object is then (in JSON notation):
{
"A": 9,
"B": 2,
// ...
"Z": 1
}
EDIT: mind the value type
If you want the value to be an actual number you will have to parse it in the assignment with:
parseInt(item[1], 10)
To create a key (property name) dynamically, you need to do one of two things:
In ES5 and earlier, you have to create the object and then set the property:
var o = {};
o[item[0]] = item[1];
In ES2015 (aka ES6) and later, you can use a dynamic property name in a property initializer via []:
// ES2015 (ES6) ONLY
quantities.push({
[item[0]]: item[1]
})
That said, I'd come at the problem differently, using regex and ending up with an object keyed by the letter rather than an array of objects:
var str = "A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1";
var quantities = {};
str.match(/[A-Z]-\d/g).forEach(function(entry) {
quantities[entry.charAt(0)] = +entry.replace(/.-/, '');
});
console.log(quantities);
Then, looking up the quantity of a letter becomes quantities.A (or quantities[letter] if letter is a variable containing "A"):
console.log(quantities.A); // 9

Categories