I am trying to understand a JavaScript code.
Banana.reloadUser is being called inside a function without any arguments:
function(data) {
if (!data.result.success) {
alert(data.result.message)
} else {
/*do something*/
Banana.testData = data;
Banana.reloadUser();
}
}
Banana.reloadUser defined like this:
Banana.extend({
reloadUser: function(cb, data) {
var that = this,
done = function(d) {
$.extend(that.user, d);
if ($.isFunction(cb)) {
cb(d)
}
that.trigger("user.reloaded", [d])
};
if (data) {
done.apply(banana, [data])
} else {
/*do something*/
}
}
})
'reloaduser' is being called to save the userinfo data in the localstorage. So whenever user do something new from its account 'reloaduser' saves the new information into the localstorage.
My question is since Banana.reloadUser is being called without arguments how is it supposed to pick its arguments ?
Note: This is a part of a big JavaScript/jquery code so in case this information is not enough please ignore the question.
The big Javascript code does contain another function
Banana.reloadUser(function() {
try {
Banana.trigger('start', [$]);
}catch(e) { }
try {
$('[data-deferred]').deferredImage();;
}catch(e) { }
});
started = true;
};
If you call a JavaScript function without arguments then all its parameters receive a value of undefined (not null which is a different value).
So calling
Banana.reloadUser()
is just the same as:
Banana.reloadUser(undefined, undefined)
In your code this is perfectly ok, the condition:
if ($.isFunction(cb)) {
will fail because undefined is not a function, and later on the condition:
if (data) {
will also fail because undefined is treated as equivalent to false when it appears somewhere that a boolean value is expected.
It is exactly similar to the below call,
Banana.reloadUser(undefined,undefined);
Related
I was cleaning up my code and ran into a little trouble with callbacks, specifically getting the correct values to output when a callback is called. Could some explain to me why the following code spits out something that I'm not expecting and a possible solution without having to put in another parameter of i to the run() function, or is passing in i to know my index upon calling the callback the only way to do this?
for (var i in dls) {
run(dls[i][0], dls[i][1], function(isTrue){
if (isTrue) {
// Do true stuff here
} else {
console.log("Value is: " + dls[i][3])
}
});
}
Calling run() actually has the correct inputs inside, but upon that function calling the callback and going into the else statement, dls[i][3] spits out the same value i times.
I've tried putting different scopes around (run()) and such but to no avail and can't seem to wrap my head around this.
Thanks
EDIT:
If I wanted to split it up into a separate function, how would I do it?
var run = function(cb){
setTimeout(function() {
cb(false)
}, 3000);
}
for (var i in dls) {
run(dls[i][0], dls[i][1], (function(index) {
return extraction
})(i));
}
function extraction(isTrue){
if (isTrue) {
// stuff
} else {
console.log("Nothing changed in " + dls[i][3])
}
}
Here dls[i][3] is still incorrect and prints the same value 3 times.
You have fallen into the traditional "loop trap"
When it comes time for your callback to run i is now a different value.
What you can do is cache that value in another wrapper function:
for (var i in dls) {
run(dls[i][0], dls[i][1], (function (currentIndex) {
return function(isTrue){
if (isTrue) {
// Do true stuff here
} else {
console.log("Value is: " + dls[currentIndex][3])
}
};
})(i));
}
In regards to the edit / second question, assuming this is what you wanted to do:
// note that I changed the function signature of `run`
var run = function(val1, val2, cb) {
setTimeout(function() {
cb(false);
}, 3000);
};
// note the `wrapper` here
for (var i in dls) {
run(dls[i][0], dls[i][1], wrapper(i));
}
// this is the same as what the IIFE is doing,
// just with an external function instead
function wrapper(scopedIndex) {
// return a function to be used as the callback for `run`
return function extraction(isTrue) {
if (isTrue) {
// stuff
}
else {
// use the scoped index here
console.log("Nothing changed in " + dls[scopedIndex][3]);
}
}
}
Take a look at function makeExitCallback(i) in the other linked question, as well. It directly relates to what's going on here.
You should post what's in dls as well, just to make it easier to run your snippets locally.
I'm attempting to simply save a string to Chrome's Local Storage, but I can't seem to do it. It could be that I've got the wrong idea about function argument implementation (after 3 years, I think I might be getting it) but any help getting this code to work would be appreciated. I wanted to make it as dynamic as possible, allowing me to take the id of any text input field I write and change the stored string appropriately.
Here's the code I've got so far:
function setData() {
dataToStore = document.getElementById('txtStore').value;
return dataToStore;
}
function storeData(data) {
localStorage.setItem('input', data);
}
btnStore.addEventListener('click', storeData(setData), false);
Is my implementation of function arguments a bit backwards? I really thought I had it this time..
When you write:
btnStore.addEventListener('click', storeData(setData), false);
storeData(setData) is executing immediately at the beginning (when you bind the click event). Therefore, it will pass the initial value of your input which is probably empty.
So you should call setData, when you store the Data:
function setData() {
dataToStore = document.getElementById('txtStore').value;
return dataToStore;
}
function storeData() {
localStorage.setItem('input', setData());
}
btnStore.addEventListener('click', storeData, false);
you would have to do this:
function setData() {
dataToStore = document.getElementById('txtStore').value;
return dataToStore;
}
function storeData(dataFunct) {
localStorage.setItem('input', dataFunct());
}
btnStore.addEventListener('click', storeData(setData), false);
you can use without argument
function setData() {
dataToStore = document.getElementById('txtStore').value;
return dataToStore;
}
function storeData() {
var data = setData();
localStorage.setItem('input', data);
}
btnStore.addEventListener('click', storeData(), false);
You're saving the value in setData, which is a function, not the value returned from the function. You have to invoke the function to get the return value.
function storeData(data) {
vare returnedData = data()
localStorage.setItem('input', data);
}
with your current code you'd have to use the above snippet. But it would make more sense to retrieve the data before invoking storeData, and not pass the function.
You need to differentiate between function invocations and function references.
btnStore.addEventListener('click', storeData(setData), false);
An event is assigned a callback - i.e. reference to a function - but you're passing it the return value of setData, which is a string, not a function.
function setData() {
dataToStore = document.getElementById('txtStore').value;
return dataToStore;
}
function storeData() {
localStorage.setItem('input', setData());
}
btnStore.addEventListener('click', storeData, false);
You should simplify it a bit using more descriptive names for your functions:
function getDataFromElement(id){
dataToStore = document.getElementById(id).value;
return dataToStore;
}
function storeData(data) {
localStorage.setItem('inputData', data);
}
function retrieveData() {
return localStorage.getItem('inputData');
}
btnStore.addEventListener('click', storeData(getDataFromElement('txtStore')), false);
This way is more generic and you can even reuse it for other elements, improve it turning that 'inputData' into a parameter.
You could also add a check to verify that local storage is available before using it:
function canStorage(){
return (typeof(Storage) !== "undefined") ? true : false;
}
It is a good idea to batch your reads and writes, say one read per page and one write per page unload. It does depends on your use case, however, storing data in memory ie. data structure until some less frequent commit action.
To write data to Window.localStorage.
localStorage.setItem(k, v);
To read data from storage
localStorage.getItem(k);
Update:
A snippet of a module I wrote in gist which provides basic functions such as;
get
set
delete
flush
has
and a few chainable functions.
Hope this helps.
Here is my issue, I have a javascript function in a .js file that performs some actions, gathers information, and uses a callback. The callback function is also a javascript function but resides in a .cshtml file. I am have difficulties returning a value from my .js javascript function to my .cshml javascript callback function.
Here is a little sample code...
my .js function which I would like to return a value from:
function returnVal(itemID, onCompleteCallback) {
//get vals from DB
onCompleteCallback();
}
my .cshtml script that calls the previous function and I need to get the returned value is a button click even:
updateBtn.onclick = function(e) {
if(action==1) {
returnVal(itemID, OnCompleted);
}
I have tried 2 methods, neither has worked. I have tried returning a value within the "returnVal" function which doesn't seem to results in anything being returned. I have also tried passing a variable as type var and setting it within the returnVal function, it was my understanding that primitives are passed by value (and thus this wouldn't work) but objects are passed by reference and so I thought this would work. At any rate, neither was successful. Bellow are examples of how I have tried the aforementioned 2 methods:
Method 1:
function returnVal(itemID, onCompleteCallback) {
//get vals from DB
onCompleteCallback();
return x;
}
updateBtn.onclick = function(e) {
if(action==1) {
x = returnVal(itemID, OnCompleted);
}
}
Method 2:
function returnVal(x, itemID, onCompleteCallback) {
//get vals from DB
onCompleteCallback();
}
updateBtn.onclick = function(e) {
if(action==1) {
var x;
returnVal(x, itemID, OnCompleted);
}
}
In both cases 'x' is not set. I hope I have provided enough details, any help would be greatly appreciated.
I think you want something like
function returnVal(itemId, onComplete){
var data = getValueFromDatabase();
onComplete(data);
}
updateBtn.onclick = function(e) {
if(action==1) {
returnVal(itemID, function(data){
// Do something with returned value i.e. 'data'
});
}
}
I'm relatively new to coding in JavaScript, and I've came across a problem. I like to nest functions to keep things orderly, but how would I exit from a parent function from inside a child function?
example:
function foo1() {
function foo2() {
//return foo1() and foo2()?
}
foo2();
}
See update under the fold
You can't. You can only return from the child function, and then return from the parent function.
I should note that in your example, nothing ever calls foo2 (As of your edit, something does). Let's look at a more real example (and one that comes up a lot): Let's say we want know if an array contains an entry matching some criterion. A first stab might be:
function doesArrayContainEntry(someArray) {
someArray.forEach(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does <-- This is wrong
}
});
return false; // No it doesn't
}
You can't directly do that. Instead, you have to return from your anonymous iterator function in a way to stop the forEach loop. Since forEach doesn't offer a way to do that, you use some, which does:
function doesArrayContainEntry(someArray) {
return someArray.some(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does
}
});
}
some returns true (and stops looping) if any call to the iterator function returns true; it returns false if no call to the iterator returned true.
Again, that's just one common example.
You've referred to setInterval below, which tells me that you're almost certainly doing this in a browser environment.
If so, your play function almost certainly has already returned by the time you want to do what you're talking about, assuming the game has any interaction with the user other than alert and confirm. This is because of the asynchronous nature of the environment.
For example:
function play() {
var health = 100;
function handleEvent() {
// Handle the event, impacting health
if (health < 0 {
// Here's where you probably wanted to call die()
}
}
hookUpSomeEvent(handleEvent);
}
The thing is, that play will run and return almost immediately. Then the browser waits for the event you hooked up to occur, and if it does, it triggers the code in handleEvent. But play has long-since returned.
Make a note whether the parent function should also return.
function foo1() {
bool shouldReturn = false;
function foo2() {
shouldReturn = true; // put some logic here to tell if foo1() should also return
return;
}
if (shouldReturn) {
return;
} else {
// continue
}
}
It only says that you can't return the parent function in the child function, but we can do a callback and make it happen.
function foo1(cb = () => null) {
function foo2() {
cb();
}
foo2();
}
foo1(() => {
// do something
});
We can use Promises for this:
const fun1 = async () => {
const shouldReturn = await new Promise((resolve, reject) => {
// in-game logic...
resolve(true)
})
if(shouldReturn) return;
}
if you wanna return from the parent function, then just resolve with true
Based on your comment, something like this might work as a main game loop.
function play() {
var stillPlaying = true;
while(stillPlaying) {
... play game ...
stillPlaying = false; // set this when some condition has determined you are done
}
}
I'm creating a Phonegap application that will perform differently on first run. The way that I am detecting the first run is by seeing of one of the database tables exists. As you can probably tell from the code below, I am checking for the error that is (probably) indicating that the table already exists, thus proving that this is not the application's first run.
function databaseExists(){
var exists;
database.transaction(function(tx){
tx.executeSql('CREATE TABLE GLOBAL (uid, property, value)');
}, function(err){
exists = true;
}, function(){
exists = false;
});
return exists;
}
My problem, however, is that the asynchronous execution of the Javascript code means that the function returns its value before the success (or error) function has set it's value.
This function is called in the initialising stage of the application:
if (databaseExists()){
// Do Something
}
And therefore must return the value rather than execute the function in the success callback of the transaction.
Is there a way to force the execution to wait until the database transaction is complete or return the value through the database.transaction object?
Thanks in advance,
Jon
You need to write it in callback form:
var dataBaseExists(yep, nope) {
database.transaction(function(tx) {
tx.executeSql('CREATE TABLE GLOBAL (uid, property, value)');
}, function(){
if (yep) {
yep.apply(this, arguments);
}
}, function(){
if (nope) {
nope.apply(this, arguments);
}
});
};
var itDoes = function() {
console.log("great");
};
var itDoesNot = function() {
console.log("what a pity");
};
databaseExists(itDoes, itDoesNot);
You need callbacks, but if don't need checking existment of your tables, you can do that easily with localStorage.
e.g.
if(localStorage.getItem('init') === null){
//init
localStorage.setItem('init', true);
}
You will avoid dealing with database.
and maybe this gonna be helpful "CREATE TABLE IF NOT EXISTS..."
I know there's gonna be programmers don't like my solution, but I love it!
var myfEspereti=false;
function Espereti(pStatus)
{
if (pStatus==="wait")
{
myfEspereti = true;
while(myfEspereti)
{
}
}
else if (pStatus==="go")
{
myfEspereti=false;
}
}
and then call Espereti ("wait") when you want to wait for an async call. Inside the async call, when it's finish, call Espereti ("go") and that's it!