Best way to re-format JS code snipet - javascript

I wanted to reformat below code in order to keep as minimum as possible Any suggestion to re-format below code and use it as one single method.
function Cookie_Exist(cookieName) {
var all_cookies = document.cookie.split(';');
for (i = 0; i < all_cookies.length; i++) {
var temp_cookie = all_cookies[i].split('=');
var cookie_name = temp_cookie[0].replace(/^\s+|\s+$/g, '');
if (cookie_name === cookieName) {
return true;
}
}
return false;
}
function Get_Cookie(cookieName) {
var all_cookies = document.cookie.split(';');
for (i = 0; i < all_cookies.length; i++) {
var temp_cookie = all_cookies[i].split('=');
var cookie_name = temp_cookie[0].replace(/^\s+|\s+$/g, '');
if (cookie_name === cookieName) {
return temp_cookie[1];
}
}
return null;
}

Instead of reparsing the cookies everytime one could do that once and build up a Map:
const cookies = new Map(document.cookie.split(";").map(pair => pair.split("=")));
Then its as simple as
cookies.get("name");
or
cookies.has("name")

If you had to keep the function Cookie_Exist rather than #Jonas's method, you would do well to use the array methods rather than a for loop. The abstraction can make code shorter and clearer:
function Cookie_Exist(cookieName) {
const allCookies = document.cookie.split(';');
return allCookies.includes(cookieStr => {
const thisCookieName = cookieStr.split('=')[0].replace(/^\s+|\s+$/g, '');
return cookieName === thisCookieName;
});
}

You don't need the Cookie_Exist() function at all, it does the same as the Get_Cookie() function. Use the Get_Cookie() everywhere instead of Cookie_Exist() and check your result. If it is false, then the cookie does not exist. As simple as that.

You may want to clarify what you mean by 'as minimum as possible.' If you're referring to being efficient, you definitely should go the route suggested by Jonas W.
If you're referring to reducing line count? His answer also is a good one, but I would recommend not focusing too much on line counts. Readability should be your number one goal. In other words, what you should be trying to keep to a minimum is the number of mental hoops a human reader of your code must jump through to understand what is going on.
Also, the regex you're doing to strip whitespace can be replaced with String.prototype.trim() which exists for this purpose.
function parseCookie(cookie) {
let { name, value } = cookie.split('=');
return [ name.trim(), value ];
}
function parseCookies() {
let cookies = document.cookie.split(';')
return new Map(cookies.map(parseCookie))
}
// Usage:
const cookieMap = parseCookies();
cookieMap.has('name');
cookieMap.get('name'):

Related

How to save create global variables (with custom name) in a private function

I'm creating an algebra math tool where I take an equation, take the terms, pair like terms, and then evaluate. (I'm making this as a coding exercise)
For the equation a + b - 2a I've gotten the terms saved in an array; ["+a", "+b", "-2a"]. Now what I want is to change this into this:
var lTERMa = ["+a", "-2a"];
var lTERMb = ["+b"];
So far my "fix" is to store the variables in a div element that has white text so you can't see it. It's rather crude, and it doesn't work. Here is the full Javascript code that I've made designed to store them in the div:
function appendinformation(info) {
document.getElementById("hiddenData").innerHTML += info;
}
function runData(bool, int) {
if (bool) {
eval(document.getElementById("hiddenData").innerHTML)
console.log()
}
eval(document.getElementById("hiddenData").innerHTML)
}
var termsViewed = 0;
var lTermsFound = 0;
var seenTerms = []
function processTERMpos(val) {
if (seenTerms.includes(val.replaceAll("+", ""))) {
termsViewed++;
appendinformation(`var lLTERM${val.replaceAll("+", "")} = [${val}]`);
runData()
}
if (!seenTerms.includes(val.replaceAll("+", ""))) {
appendinformation(`lTERM${val.replaceAll("+", "")}.push(${val})`)
runData()
seenTerms.push(val.replaceAll("+", ""))
lTermsFound++;
termsViewed++;
}
}
function processTERMneg(val) {
if (seenTerms.includes(val.replaceAll("-", ""))) {
termsViewed++;
appendinformaion(`var lLTERM${val.replaceAll("-", "")} = [${val}]`);
runData()
}
if (!seenTerms.includes(val.replaceAll("-", ""))) {
appendinformation(`lTERM${val.replaceAll("-", "")}.push(${val})`)
runData()
seenTerms.push(val.replaceAll("-", ""))
lTermsFound++;
termsViewed++;
}
}
for (var i = 0; i < term.length; i++) {
var subject = term[i]
getHiddenData();
eval(hdata);
if (subject.includes("+")) {processTERMpos(subject)}
if (subject.includes("-")) {processTERMpos(subject)}
}
Don't bully me for my bad disorganised coding. I've deleted and reinstated various code, and I'm sure there is code in there than no longer has a use.
If someone could either fix my code, or be able to suggest another way for me to attempt rewriting the code. I've been deleting and rewriting this code for 2 hours and I can't think of any way I can fix it.

FreeCodeCamp: checking for palindromes

This is my first question, so I apologize if this isn't formatted correctly or placed in the proper area.
I just completed the FreeCodeCamp checking for palindromes challenge. I can't help but think my solution was very inelegant.
function palindrome(str) {
var cleanString = str.replace(/[^A-Za-z0-9]/g, '');
var lowerCleanString = cleanString.toLowerCase();
var lowerArr = lowerCleanString.split('');
var reverseArr = lowerArr.reverse();
var joinedArr = reverseArr.join('');
if (joinedArr === lowerCleanString) {
return true;
}
// Good luck!
else {
return false;
}
}
I know it worked, but is it possible to do some of these steps together or in a cleaner way?
Simple function to check for palindromes
function checkPalindrome(palindrome) {
return palindrome == palindrome.split('').reverse().join('');
}
function palindrome(str) {
var newstr = str.replace(/[\W_]/g,'').toLowerCase();
if(newstr === newstr.split('').reverse().join('')){
return true;
}
return false;
}
palindrome("five|\_/|four");
You can use many methods in one row like I've used them .It's more simple :)
Good luck
Wow, I really like the answers comparing the string to a string.split('').reverse().join('') version of itself. I didn't think about that. Forgot about the .reverse() function. I ended up processing the string and splitting it out into an array and then using a double counter for the loop to compare the first and last items in the array. Was kinda fun to learn how to do that, but I like the .reverse() function use better.
In case someone is curious about the for loop I used ...
for(let i = 0, j = arr.length-1; i < j; i++, j--) {
if (arr[i] !== arr[j]) {
return false;
}
}

Recursive function for clearing zeros in an array/string

I need a function where I can clear off the zeros which appears at the beginning of my string, basically something like '0000213' in javascript. I just want the '213' and not the zeros. Here is the code that I have written but theres some problem with the array length in the for loop, can someone please help me with this. https://jsfiddle.net/066by2cv/3/
Try this solution.
'0000213'.replace(/0+/,'');
or
Number('0000213').toString();
or just
+'0000213' + ''
Although already answered by #Tresdin, in case you really want your function, you can use
var str = '0003';
function Iterate(val) {
var start = 0;
for (var i = 0; i < val.length; i++) {
if (val.charAt(i) == '0') {
start = i;
}
}
return val.substr(start+1);
}
var re = Iterate(str);
alert(re);

Counter array in Javascript

I am trying to make two arrays. the unique array can get the elements (no repeats) from the text array, and the counter one can count the frequency of each elements. but something is wrong with the counter one.
var unique_array=new Array();
var counter_array=new Array();
var unique=true;
for (i=0;i<text_array.length;i++){
if (unique_array.length==0){
unique_array.push(text_array[0]);
counter_array.push(1);
}
else if(unique_array.length>0&&unique_array.length<=text_array.length){
for (j=0; j<unique_array.length;j++){
if (text_array[i]==unique_array[j]){
counter_array[j]=counter_array[j]+1;// something wrong with the
alert(counter_array[j]);
var unique=false;
}
}
if (unique==true){
unique_array.push(text_array[i]);
counter_array.push[1];
}
unique=true;
}
You could also simplify the code down using a hashmap and some ES5 higher-order functions:
var text_array = ["a1","a1","a2","a3","a2","a4","a1","a5"];
var counts = {};
text_array.forEach(function(el) {
counts[el] = counts.hasOwnProperty(el) ? counts[el]+1 : 1;
});
var unique_array = Object.keys(counts);
var counter_array=unique_array.map(function(key) { return counts[key]; })
You can do this much more simply using an object. Let the values be the keys of an object, then just increment the count of each property as you go. At the end, you can get an array of the unique keys and their values:
var text_array = ['foo','bar','foo','fum','fum','foo'];
var i = text_array.length;
var obj = {};
while (i--) {
if (obj.hasOwnProperty(text_array[i])) {
obj[text_array[i]]++;
} else {
obj[text_array[i]] = 1;
}
}
console.log('Unique values: ' + Object.keys(obj)); // Unique values: foo,fum,bar
console.log('Value counts: ' + Object.keys(obj).map(function(v){return obj[v]})); // Value counts: 3,2,1
Note that the sorting of counts in the output is purely coincidental.
As Jasvir posted, you can make it pretty concise:
var obj = {};
text_array.forEach(function(v) {
obj.hasOwnProperty(v)? ++obj[v] : obj[v] = 1;
});
But the first example is a bit easier to digest.
I think the approach is what's making it difficult. A hash table / associative array would be much easier to work with.
With a hash table (an object {} in JS), you can store each word in a key and increment the value of the key when you encounter the word again. Then, at the end, just go through the hash table and gather up all the keys which have small values. Those are your unique words.
function get_unique_words(text_array) {
var hash_table, i, unique_words, keys;
hash_table = {};
for(i = 0; i < text_array.length; i++) {
if(hash_table[text_array[i]] === undefined) {
hash_table[text_array[i]] = 1;
} else {
hash_table[text_array[i]]++;
}
}
// go through the hash table and get all the unique words
unique_words = [];
keys = Object.keys(hash_table);
for(i = 0; i < keys.length; i++) {
if(hash_table[keys[i]] === 1) {
unique_words.push(keys[i]);
}
}
return unique_words.sort();
}
console.log(get_unique_words(
['blah', 'blah', 'blah', 'goose', 'duck',
'mountain', 'rock', 'paper', 'rock', 'scissors']
));
Some issues and suggestions :
Don't use var twice for the same variable.
Browsers deal with it ok, but for clarity you should only be declaring your variables once.
Always localize your loop counters - forgetting a var before your i and j will cause them to become global variables.
This is relevant when you have a page with lots of code - all global variables will show up in the debugger's watch list at all times, making it harder to debug your code.)
Use the array literal notation [] instead of the function form Array.
The function form is longer and it's easier to forget the new. It's also easier to read (IMO).
Use more whitespace (it won't bite), such as before and after an equals sign:
var x = 1;
// vs.
var x=1;
It makes the code easier to read and most people don't overdo it.
Indent your code when it's inside a block (e.g. function, if, else, while, for, etc.).
This makes it easier to read the control flow of the code and will help prevent bugs.
Use three equals signs (===) unless you are using loose equality on purpose.
This will help someone looking at your code later (probably yourself) understand better what the test is supposed to be testing.

Easy way to evaluate path-like expressions in Javascript?

If I have a JavaScript object such as:
var x = {foo: 42, bar: {fubar: true}}
then I can get the value true with var flag = x.bar.fubar. I'd like to be able to separate out and store the path "bar.fubar", then evaluate it dynamically. Something like:
var paths = ["bar.fubar", ...];
...
var flag = evalPath( x, paths[0] );
Obviously I could write a simple parser and evaluator for a basic path expression grammar. But under DRY principles I wonder if there's already an existing way to do something like evalPath built-in to JavaScript, or a small library that would do the job? I also anticipate needing array indexes in the path expression in future.
Update Just to be clear, I'm not asking for code samples - my question is whether there's existing code (built-in or library) I can re-use. Thanks to the contributors below for suggestions of code samples anyway! Note that none of them handle the array index requirement.
Doing a quick search, I came across JSONPath. Haven't used it at all, but it looks like it might do what you want it to.
Example usage:
var x = {foo: 42, bar: {fubar: true}}
var res1 = jsonPath(x, "$.bar.fubar"); // Array containing fubar's value
Why not try something like
function evalPath(obj, path)
{
var rtnValue = obj;
// Split our path into an array we can iterate over
var path = path.split(".");
for (var i = 0, max=path.length; i < max; i++)
{
// If setting current path to return value fails, set to null and break
if (typeof (rtnValue = rtnValue[path[i]]) == "undefined")
{
rtnValue = null;
break;
}
}
// Return the final path value, or null if it failed
return rtnValue;
}
Not tested, but it should work fairly well. Like XPath, it will return null if it can't find what it's looking for.
JavaScript provides eval, but I don't recommend it.
like
function locate(obj, path) {
var p = path.split("."), a = p.shift();
if(a in obj)
return p.length ? locate(obj[a], p.join(".")) : obj[a];
return undefined;
}
locate(x, "bar.fubar")
this works on the right only, of course
You could try something like this. I can't really think of a situation where it would be appropriate to store paths this way though.
function evalPath(obj, path) {
var pathLevels = path.split('.');
var result = obj;
for (var i = 0; i < pathLevels.length; i++) {
try {
result = result[pathLevels[i]];
}
catch (e) {
alert('Property not found:' + pathLevels[i]);
}
}
return result;
}
The alert is really only there for debugging purposes. You may want to return null or something.
How about:
evalPath = function(obj, path) {
if (path[0] === "[") {
return eval("obj" + path);
} else {
return eval("obj." + path);
}
};
This has the advantage that it works for arbitrary strings:
evalPath([1,2,3], "[0]"); => 1
evalPath({a:{b:7}}, "a.b"); => 7
This, of course, only works if you really trust your input.

Categories