How to use an expression in the Object literal key? - javascript

I have a switch^
let s = "aaa"
switch (true) {
case s.includes('a'):
url = 'https://a.com/wp-admin/post-new.php'
console.log(url)
break
case s.includes('b'):
url = 'https://b.com/wp-admin/post-new.php'
console.log(url)
break
default:
console.log('default')
break
}
I'm trying to change this to a literal object, but I can't figure out how to properly specify the s.includes condition as the object key
const objLit = (s) => {
const cases = {
//s.includes('a'): 'https://a.com/wp-admin/post-new.php',
[`${s.includes('a')}`]: 'https://a.com/wp-admin/post-new.php',
//s.includes('b'): 'https://b.com/wp-admin/post-new.php',
[`${s.includes('b')}`]: 'https://b.com/wp-admin/post-new.php',
}
let url = cases[s]
return url
}
console.log(objLit(s))
Although this does not throw an error, it does not work.

You can't. Property names are strings or Symbols.
When you use [] syntax, the expression is evaluated at object creation time.
You can't assign code that gets evaluated at lookup time. This is what switch and if/else are for.
In your case, since includes() returns a boolean, you are just creating an object with properties named "true" and "false".
You could say let url = cases.true, but it would be a horrible hack.

Related

JavaScript and Consts [duplicate]

This question already has answers here:
How to use a variable for a key in a JavaScript object literal?
(16 answers)
Closed 4 months ago.
const A = 0;
const LOOKUP = { A : "A"};
console.log(LOOKUP[A]);
console.log(LOOKUP[0]);
Result:
undefined
undefined
Second try:
var A = 0;
const LOOKUP = { A : "A"};
console.log(LOOKUP[A]);
console.log(LOOKUP[0]);
Result:
undefined
undefined
How am I supposed to do this then? And can somebody explain why this doesn't work in JavaScript the way one would expect it to work coming from other languages?
The correct way is:
const A = 0;
const LOOKUP = {};
LOOKUP[A] = 'A';
console.log(LOOKUP[A]);
console.log(LOOKUP[0]);
const LOOKUP = { A : "A"};
The left side of the colon means that the key is the string "A". The string part is implicit, since all keys are strings (or symbols). So to access the property, you need to do console.log(LOOKUP.A) or console.log(LOOKUP["A"])
If you want the key to be a computed value, then you need to use square brackets:
const LOOKUP = { [A]: "A" };
That means that we should resolve the variable A, and use its value as the key. That key is the number 0, which then gets coerced into the string "0". You can then look it up by any of console.log(LOOKUP["0"]), console.log(LOOKUP[0]), or console.log(LOOKUP[A])
Looks like you are searching for some enums (typescript):
enum ETest {
A = 1
};
console.log(ETest['A']); // 1
console.log(ETest[1]); // A
Doing LOOKUP[A] is like doing LOOKUP[0] which is undefined.
You should try it as
console.log(LOOKUP["A"])
This has nothing to do with const or var keyword. The way you are trying to access an object property is incorrect.
const A = 0;
const LOOKUP = { A : "A"};
console.log(LOOKUP["A"]); // Correct Approach: Property access through bracket notation should be done using a string (or a variable assigned to a string).
console.log(LOOKUP[0]); // Property `0` doesn't exist on object `LOOKUP`, so it'll return `undefined`.

Converting string to a type (node.js)

I know this seems like an odd problem, but at the moment I'm creating a webserver to save data to a mongodb database using mongoose. To use that, I need to create a model with a schema which basically defines the values I can search to, as well as the type they should be (String, Number, etc.)
As I said before, since it's a webserver, I'd like to make it so the webserver will create the model and the schema, with a body object in the request. However, there is an issue. I can only pass the type (String, Number, etc.) as a string. I've come up with a solution to parse the value into a type, that being the code below
getTypeByString: function (string) {
if (string == 'String') {
return String
}
if (string == 'Number') {
return Number
}
if (string == 'Array') {
return Array
}
if (string == 'Object') {
return Object
}
}
However, I feel like there is probably a more simple solution. If there is or isn't, please let me know! I'd like to release my code on GitHub eventually, and I'd like it to be as dynamic and simple as possible. Thank you in advance
String, Number, Array and Object are also properties of the global variable (or window variable if you are in a browser).
You can check it yourself by evaluating:
global['String'] === String // true
For this reason, you can just use the string to lookup the type within the global object, and return it:
getTypeByString: function (string) {
if (['String', 'Number', 'Array', 'Object'].includes(string)) // be sure that you are actually returning a type
return global[string];
return null;
In regards to getting a defined type from a string you can use an object to define the types and use the string as the key.
const DefinedTypes = {
String: String,
Number: Number,
Array: Array,
Object: Object,
CustomType: classOfCustomType
};
Using it.
const typeAsString = 'String';
const type = DefinedTypes[typeAsString];
You could use a switch statement to make the code a bit simpler:
getTypeByString: function(stype){
switch(stype){
case "String": return String;
case "Number": return Number;
case "Array": return Array;
case "Object" : return Object;
default: return null; // or throw an error
};
};

How to split ``(Backtick string) on each instance of ${variable}

So my question is how i can split the a string with backtick on each instance of variable.
I tried with \${.*?} but this will not work because ${variable} will be replaced by variable values first and than the split function will be executed.
Any idea how to do it ?
let a = 2
let b = 4
let x = `Superman${a}hello${b}one more`.split(/\${.*?}/g)
console.log(x)
On side not: I don't want a solution with wrapping it to " or '.
console.log('`Superman${a}hello${b}one more`'.split(/\${.*?}/g))
After the line executes, there is no way to get the original template string. However, you can use a tag function/tagged template literal to get the parts of the string, including the substitution values:
function Test() {
console.log(arguments)
return arguments.length - 1
}
let a = 2
let b = 4
let c = Test `Superman${a}hello${b}one more`
console.log(`This template string has ${c} substituted values`)
To clarify my comment to the original question here is an example of what the default Template Literal Function does:
function defaultTemplateLiteralFn(strs, ...args) {
return strs.map((str, idx) => str+(args[idx]||'')).join('');
}
const test = "special test";
const a = 10;
const b = 432;
console.log(`This is a ${test}. "${a}+${b}=${a+b}"`)
console.log(defaultTemplateLiteralFn`This is a ${test}. "${a}+${b}=${a+b}"`)
When you use a tagged template (IE: You don't provide a function to handle the template literal) The the language provides a default function that does something similar to what I do in my function defaultTemplateLiteralFn above. It returns the combined parts of the string with the values.
The example function takes each part of the string and puts the appropriate value after the string. If there is no value then it uses a blank string.
One way i have done is using template literal. i have seen this is being used in a in a library called styled-components which allows us to write css with js.
Would love to see other methods if there are any ?
function splitOnVariable(str, age){
// first argument to function will always be array of strings provided in input string.
return str
}
let a = 1;
let b = 2;
console.log(splitOnVariable`hello${a} break me on variable${b} !!!`)

How does JSON.stringify make memoize function work?

_ .memoize = function(func) {
var hash = {};
return function() {
var arg = JSON.stringify(arguments);
if (hash[arg] === undefined) {
hash[arg] = func.apply(this, arguments);
}
return hash[arg];
};
};
Hello,
I am trying to implement the memoize underscore function. I have a question regarding to JSON.stringify.
In the if statement where it checks if the arg already exist or not in the hash. Why using JSON.stringify make it possible to check wether the input arg exist or not in the hash. I mean if we pass the arguments array without converting them using JSON.stringify, then we cannot check because we are passing an entire array. However, when using JSON.stringify, it makes it work. So how does JSON.stringify make it possible to check ?
The hash is a JavaScript object, which uses strings as keys. You cannot use an array (or array-like, in the case of arguments) there, so it needs to be converted to a string.
If no custom conversion is done, then the default serialisation would be "[object Arguments]" for any value of arguments. This is not unique and will not work with the intention of memoization.
var hash = {};
var i = 0;
//a naive function that takes anything and puts it in a hash with a unique value
function populateUnique() {
hash[arguments] = "Hello" + i;
i++;
}
populateUnique("a");
populateUnique("b");
populateUnique("c", "d", "e");
console.log(hash); //only shows the last thing, as it it's always overridden.
This implementation chooses to employ JSON.stringify because it is quite straight forward - you could implement a custom serialisation function, but there is already one provided, so this is the simplest way to do it.
Should be noted that JSON.stringify is not bulletproof. It is easy to use and covers a lot of cases, but may blow up, for example, if you have circular references:
var foo = {};
foo.bar = foo;
JSON.stringify(foo);
Since the memoize function does not control what will be passed in as arguments, it's possible that one of them, that is normally perfectly valid, will throw an error.
Another problem is if any of the arguments has its own toJSON method - this will be used for serialization, so you could end up in an interesting situation:
var a = 42;
var b = {
firstname: "Fred",
lastname: "Bloggs",
id: 42,
toJSON: function() { return this.id }
}
console.log(JSON.stringify(b));
console.log(a == JSON.stringify(b));
It's because only strings can be used as keys in javascript objects.
For example:
var key = {a:1};
var map = {};
map[key] = 1;
// {'[object Object]': 1}
This will result in every arguments combination being saved in the same key.
Using JSON.stringify transform the arguments list in an unique string that can in turn be used as an unique object key.
var key = {a:1};
var map = {};
map[JSON.stringify(key)] = 1;
// {'{"a":1}': 1}
This way, every time you call the function with the same arguments, JSON.stringify will return the same unique string and you can use that to check if you already have a cached result for that set of arguments, and if so, returning the cached value.

How to use String representation of object property, operator, and value?

I'm trying to use a string value of say, "[ScheduledDate] < '11/1/2011'", and test for a bool value on an object like "item". But I can't seem to be able to figure out a way to do it successfully. I'm not wanting to use the eval function, but if it's the only way, then I guess I will have to. below is an example of the function I'm trying to use.
function _filterItem2() {
var item = { ScheduledDate: '1/1/2012' };
var filterExpression = "[ScheduledDate] < '11/1/2011'";
var result = item[filterExpression]; // This is where I'm not sure.
return result;
}
No, item[filterExpression] would just return the property named like your string.
Instead, you should store your filter expression as an object:
var filter = {
propname: "ScheduledDate",
operator: "<",
value: "1/1/2012"
};
Then get your comparison values:
var val1 = item[filter.propname],
val2 = filter.value;
and now comes the tricky part. You are right, you should not use eval. But there is no possibility to get the corresponding functions from operator names, so you will need to code them yourself. You might use a switch statement or a map like this:
var operators = {
"<": function(a,b){return a<b;},
">": function(a,b){return a>b;},
...
};
var bool = operators[filter.operator](val1, val2);

Categories