javascript how to change function from imperative to functional - javascript

i am new in functional programing, and developing web app using angularjs. I am try to change some formal function to functional. functional method has one entry and only one return, and should no side effect inside function. but in my function i change the status in for loop, so i guess i have to separate below to several block?
imperative return true/false and change status in one circle of for loop
what i expected is that change to functional and no additional for loop
function checkStatusOfChildTest(childList) {
for (var i = 0; i <childList.length;i++) {
var keys = Object.keys(childList[i]);
if (keys.length === 1 && keys[0] === '$status') {
if (childList[i][keys[0]] === 'create') {
return true;
} else {
//just mark the status of child as delete, then remove child when save finally
childList[i][keys[0]] = 'delete';
return false;
}
}
}
//if no status is new one
return true;
}

Related

How to loop through a JS set and break when a value is found?

I have 2 sets of URLs. I want to loop through one set and compare each value with .has to the 2nd set.
To that effect I have:
urlSet1.forEach(function(value) {
if (urlSet2.has(value) == false) {
newUrl = value;
return false;
}
})
However, of course, this keeps continuing to loop through.
I tried using every but I get the error:
urlSet1.every is not a function
And of course break; does not work on this either.
Would anyone know how to achieve this?
You should use a for loop.
for( const url of urlSet1 ) {
if( !urlSet2.has(url) ) {
newUrl = url;
break;
}
}
If your goal is to continue running the loop until the condition is met, then you can nest your conditional logic inside a while loop and use a boolean flag to stop the loop from running.
Optionally, you could also use a break; now that a while loop is being used but a boolean flag works just as well without needing to rearrange your logic.
See notes within the snippet below:
var urlSet1 = new Map()
urlSet1.set('abc.com', 'def.com', 'ghi.net', 'jkl.com')
var urlSet2 = new Map()
urlSet2.set('abc.com', 'def.net', 'ghi.com', 'jkl.com')
var newUrl = ''
//set a boolean flag to use as condition for while loop
var running = true
//while running is true, continue running loop
while (running) {
urlSet1.forEach(function(value) {
if (urlSet2.has(value) == false) {
newUrl = value;
console.log(newUrl)
//once condition is met, set boolean flag to false to stop loop
running = false;
console.log(running)
} else {
//some other condition
}
})
}

JavaScript loop through all existing objects to find an object key

I am trying to debug a system that was built by someone else. I have a minified library that makes an ajax (xhr) call to an external data source and writes the received data to an object or a variable. The call is made immediately after page load so I can't catch it by appending a function to register all XHR call requests. So I am trying to run a loop through all variables and objects that the browser window has. I am trying this:
var foundVar = false;
loopThroughObject(this);
function loopThroughObject(obj) {
if (!foundVar) {
try {
for (var name in obj) {
if (obj[name] && {}.toString.call(obj[name]) === '[object Function]') { //making sure that the object is not a function
} else {
if (name == 'searchedKey') { //found the object with key = searchedKey
console.log(obj[name]);
foundVar = true;
} else {
setTimeout(loopThroughObject.bind(null, obj[name]), 10); //do more recursion of inner objects
}
}
}
} catch (error) {}
}
}
The problem is that the setTimeout(loopThroughObject.bind(null, obj[name]), 0); part stacks up and a memory issue occurs. I tried the simple loopThroughObject(obj[name]), but I am facing the "Too much recursion" error after 25000 loops. It also seems that I am missing something and it causes the loop go through some object types that I don't need. Does anyone know a more efficient way to do that loop?
P.S. I tried a very simple HTML page and the code works fine:
<html>
<head>
<script>
var test = JSON.parse("{\"searchedKey\":\"12\"}");
</script>
</head>
<body>
</body>
</html>
The problem is almost certainly the fact that window has several properties that point back to itself, so your code is going into an infinite loop. There may well be other circular references.
You can remember what objects you've already looked in using a Set, like this (I've also added a few other tweaks; for instance, you can check for a function with typeof x === "function"):
let foundVar = false;
let seen = new Set();
loopThroughObject(this);
function loopThroughObject(obj) {
if (!foundVar) {
try {
for (const name in obj) {
const value = obj[name];
if (typeof value !== "function") {
if (name == "searchedKey") { // found the object with key = searchedKey
console.log(value);
foundVar = true;
break;
} else if (value && typeof value === "object" && !seen.has(value)) {
seen.add(value);
loopThroughObject(value); // No need for setTimeout
}
}
}
} catch (error) {}
}
}

Finding a cycle in singly linked list with javascript (Is my solution efficient)

My solution works well if the starting node is passed to the function correctly. I want to know if my solution is good and efficient. I should be able to return true if the cycle exists via function to which first node is passed as parameter. I would like to know if my solution is efficient especially for an interview setting. My comments in the code are self explanatory. Im using a variable track to traverse through the list and checking for a null or head as the next. If i encounter any of them traversal ends and then individually i check for null or head condition and based on that i return the appropriate boolean value.
function SLLNode(elem) {
this.value=elem;
this.next=null;
}
var hasCycle=function(node){
var track=node;
//traverse thru list till next node is either null or back to first node
while(track.next!==null && track.next!==this.head){
track=track.next;
}
if(track.next === null){ //if next node null then no cycle
return false;
}
if(track.next===this.head){ //if next node head then there is cycle
return true;
}
}
var my_node1=new SLLNode(3);
var my_node2=new SLLNode(5);
var my_node3=new SLLNode(19);
//assigning head
var head=my_node1;
//connecting linked list
my_node1.next=my_node2;
my_node2.next=my_node3;
my_node3.next=my_node1; //cycle
console.log("Has cycle?: "+hasCycle(my_node1)); //outputs true as expected
var node1=new SLLNode(3);
var node2=new SLLNode(5);
var node3=new SLLNode(19);
//assigning head
var head1=node1;
node1.next=node2;
node2.next=node3;
console.log("Has cycle?: "+hasCycle(node1)); //outputs false as expected
JSON.stringify() can be used to detect cyclic linked lists. CircularDetector returns true if the linked list is cyclic.
function CircularDetector (head) {
try {
JSON.stringify(head);
return false;
} catch (e) {
return true;
}
}
You can read more on cycle detection at https://en.wikipedia.org/wiki/Cycle_detection but the main takeaway is that if you move one pointer twice as fast as another pointer then a loop would be identifiable as the fast pointer will eventually catch up with the other. Here's a possible solution in js.
function hasCycle(head) {
var slow, fast;
if(!head || !head.next) return false;
slow = head;
fast = head;
if(head.next === head) return true;
while(fast.next.next) {
slow = slow.next;
fast = fast.next.next;
if(slow === fast) return true;
}
return false;
}
Not a very efficient solution as I am using map but if you don't want to use two pointers this solution is easy to understand
// Preparation code:
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
function hasCycle(head) {
let node = head;
let map={};
while(node){
if(map[node.value]){
//return node or true
return {"Found":node}
}
else{
map[node.value] = true;
}
node = node.next;
}
return "Not found";
}
const nodeA = new Node('A');
const nodeB = nodeA.next = new Node('B');
const nodeC = nodeB.next = new Node('C');
const nodeD = nodeC.next = new Node('D');
const nodeE = nodeD.next = new Node('E');
console.log(hasCycle(nodeA)); // => null
nodeE.next = nodeB;
console.log(hasCycle(nodeA))

How to handle callbacks in JavaScript within recursive functions?

Trying to compare two sub trees of bookmarks in Chrome, I ran into troubles with the asynchronous API call to query the children of a bookmarks folder.
function titleComparator (lhs, rhs) {
return lhs.title < rhs.title ? -1 : lhs.title > rhs.title ? 1 : 0;
}
// Return whether two bookmark trees have equal content
function compare(lhs, rhs) {
// Not equal if one is a bookmark and another is a folder
if (('url' in lhs) != ('url' in rhs))
return false;
// If both are bookmarks, compare url and title
if ('url' in lhs && 'url' in rhs)
return lhs.title == rhs.title && lhs.url == rhs.url;
// If both are folders, compare contents
chrome.bookmarks.getChildren(lhs.id, function (lhsChildren) {
chrome.bookmarks.getChildren(rhs.id, function (rhsChildren) {
if (lhsChildren.length != rhsChildren.length)
return false; // Want to return from compare()
lhsChildren.sort(titleComparator);
rhsChildren.sort(titleComparator);
for (var i = 0; i < lhsChildren.length; i++)
if (!compare(lhsChildren[i], rhsChildren[i])
return false; // Same here
return true; // Same here
});
});
}
How to handle callbacks in JavaScript within recursive functions?
as explained in detail here
you will need to refactor your code.
somehow it seems that it is not the correct way to use recursion within a asynchronous (often delayed) function to search a tree-based or hierarchical data model.
I think this should be the way to do it:
Seperatate the logic into several functions
Use "lazy loading" to avoid duplicate call of getChilden()
Use recursion and define a new nested function callback
Refactor the for-loop to recursion as well
See my untested code to show what I mean:
function compare(lhs, rhs, callback, index, lhsChilds, rhsChilds){
// Not equal if one is a bookmark and another is a folder
if (('url' in lhs) != ('url' in rhs)) {
callback(false);
return;
}
// If both are bookmarks, compare url and title
if ('url' in lhs && 'url' in rhs) {
callback(lhs.title == rhs.title && lhs.url == rhs.url);
return;
}
// If both are folders, check parameters and compare contents
//First, check if the list has already been loaded (code is running inside a recursive step)
if(lhsChilds != undefined && rhsChilds != undefined){
compareTwoChilds(lhs, rhs, callback, index, lhsChilds, rhsChilds);
}
else{
index = 0; //first recursion for this tuple (lhs, rhs)
chrome.bookmarks.getChildren(lhs.id, function (lhsChildren) {
chrome.bookmarks.getChildren(rhs.id, function (rhsChildren) {
compareTwoChilds(lhs, rhs, callback, index, lhsChilds, rhsChilds);
});
});
}
}
function compareTwoChilds(lhs, rhs, callback, index, lhsChilds, rhsChilds){
if (index < lhsChildren.length){ //just for the safety
if (lhsChildren.length != rhsChildren.length) {
callback(false);
return;
}
lhsChildren.sort(titleComparator);
rhsChildren.sort(titleComparator);
//compare using recursion, with an emtpy lists of rhs and lhs children
compare(lhsChildren[index], rhsChildren[index], function(compareResult){
if(!compareResult){
callback(false); //if the result is false, no more search needed
}else{ // use recursion again to loop through the next childs using the already loaded childs
if (++index < lhsChildren.length){
compare(lhsChildren[index], rhsChildren[index], callback, index, lhsChilds, rhsChilds)
}else{
callback(true); // the loop has ended,
}
}
});
}else{
callback(false); //this should never happen, so not the same...
}
}
you can call the compare function like that:
compare(lhs,rhs, function(result){
var compareResult = result;
//carry on with your code here
});
//and not here :-)
return will only ever exit the callee
You're gonna have to provide a callback for the answer to be spat out into asynchronously.
Everywhere you've written a return statement intended to be consumed by the callback closure, you should standardize instead on passing it to your callback.
function compareAsync(lhs, rhs, callback) {
//…
callback(false); return;
//…
callback(lhs.title == rhs.title && lhs.url == rhs.url); return;
//…
callback(false); return; // Want to return from compare()
//…
var finished = 0;
var whetherSuccess = true;
lhsChildren.forEach(function(iterand, index) {
compareAsync(iterand, rhsChildren[index], function(result) {
whetherSuccess &= result;
if (++finished === lhsChildren.length) {
callback(whetherSuccess);
}
});
});
}
So: upon finding out what the lhsChildren are, we kick off a bunch of async functions. They'll each increment the finished counter at some point. They each have the power to demote the overall whetherSuccess to false via &=. The consumer who discovers they're the the final function to get an answer, is the person who will report whetherSuccess to the original callback.
First of all, I found that Chrome has a getSubTree() function as well which makes things considerably easier. So if you just want to get it work, use this instead of asynchronously traversing the tree node by node. However, this remains an interesting problem and thanks to a reddit user, I figured out a working solution to this.
compare() is the main function that recursively calls itself. However, because of the asynchronous call inside, it cannot consume the return values of it's recursive calls.
// Pass a boolean to the callback indicating whether the recursive contents of
// both bookmarks folders are equal.
function compare(lhs, rhs, callback) {
// Compare titles except for the top-level folder
if (lhs.parent_ && lhs.title !== rhs.title) {
compare_failure(callback);
return;
}
// Compare urls if at least one of the sides is a bookmark
if ('url' in lhs || 'url' in rhs) {
if ((lhs.url || null) === (rhs.url || null))
compare_respond(lhs.parent_, callback);
else
compare_failure(callback);
return;
}
// For both sides being folders, we have to take a look at the contents
chrome.bookmarks.getChildren(lhs.id, function (lhs_children) {
chrome.bookmarks.getChildren(rhs.id, function (rhs_children) {
// Compare amount of children
if (lhs_children.length != rhs_children.length) {
compare_failure(callback);
return;
}
// Keep track of how many children already reported back
lhs.all_children = lhs_children.length;
lhs.equal_children = 0;
// Let pairs of children compare each other
lhs_children.sort(bookmark_comparator);
rhs_children.sort(bookmark_comparator);
for (var i = 0; i < lhs_children.length; i++) {
var lhs_child = lhs_children[i];
var rhs_child = rhs_children[i];
// Store parent reference so the deeper function can
// asynchronously respond with the results once finished.
lhs_child.parent_ = lhs;
compare(lhs_child, rhs_child, callback);
}
});
});
};
compare_respond() is the counterpart that is used to propagate results of deeper nodes back up. It's used instead of return in the main function above.
// Report comparison results back to the parent node. The parent node waits
// until it collected the results from all its children. Then it reports to
// its parent in turn. At the root node, the user callback is executed.
function compare_respond(node, callback) {
// Collect child results
node.equal_children++;
// Respond upwards if we got results from all
if (node.equal_children == node.all_children) {
if ('parent_' in node)
compare_respond(node.parent_, callback);
else
callback(true);
}
};
compare_failure() is used to abort the whole thing at any point when we found a pair of unequal nodes. We don't have to report upwards in that case.
// Break out of the recursive function and report failure to the user. It's
// safe against being called multiple times so multiple children can report
// failure and the user will only be notified once.
function compare_failure(callback) {
if ('called' in callback)
return;
callback.called = true;
callback(false);
};
bookmark_comparator() is a small helper that is used to sort arrays of child bookmarks. Sorting is needed to compare the contents of two folders since I don't want to rely on the item order.
// Comparator to sort lists of bookmark nodes first by title and second by
// url. Take into that folders have to url.
function bookmark_comparator(lhs, rhs) {
if (lhs.title != rhs.title)
return lhs.title < rhs.title ? -1 : 1;
if (lhs.url || null != rhs.url || null)
return lhs.url || null < rhs.url || null ? -1 : 1;
return 0;
};

How to call javascript function without changing its previous value?

I need to call a javascript function any number of times without changing the previous vales of it.
I have a json called icon which has 15 icons in it
and i am using switch statement to call the function of respective icon.
I have problem when map icon comes, because map icon usually groups all icons which means it can have even another map icon in it. Below is my code.
for(var i = 0;i<icon.length;i++) {
switch(icon.type) {
case 1:
display();
case 2:
map();
..
}
}
And the map function will be like
function map() {
for(var i = 0;i<icon.length;i++) {
switch(icon.type) {
case 1:
display();
case 2:
map();
..
}
}
}
If a map function calls its own function again, the values in the main map function overrides. I dont know how to make a call to its own function without changing the previous values..
Is there any other way to achieve this?
I do not know if I understood correct Your problem, but You can try to use technique called memoization. It is used to cache result of a previously calculated value thus can avoid the need to recalculate.
And here is simple example how this could be done
function isPrime(value) {
if (!isPrime.anwers) isPrime.answers = {};
if (isPrime.answers[value] != null) {
return isPrime.answers[value];
}
var prime = value != 1; // 1 can never be prime
for (var i = 2; i < value; i++) {
if (value % i == 0) {
prime = false;
break;
}
}
return isPrime.answers[value] = prime;
}

Categories

Resources