$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
I would like to be able to use the data in every function I make, that's why I tried to put it in the variable astronautsData, but unfortunately astronautsdata is undefined.
You can access astronautsData inside doSomething.your alert() will get executed
before getJSON. that's why you are getting undefined.
$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
alert(astronautsData.people[0].name)
}
});
Here you must understand one thing that getJSON is 'async'. Your alert method trying to show the data which gonna come in future. In order to solve this problem, you must use 'then', 'done' or 'fail' like below.
$(function(){
var astronautsData;
//Assign your getjson request
var jsonRequest = $.getJSON('http://api.open-notify.org/astros.json');
//This function runs once the getJSON method is success
jsonRequest.done(function(data){
astronautsData = data;
});
//This function runs after the success of getJSON
jsonRequest.then(function(){
//Here you have to do your alert ( This alert will give data )
alert(astronautsData);
});
//This alert will give undefined value as this line of code and getjson request runs parallelly
alert(astronautsData);
});
Your .getJSON is asynchronous.
Try using a Promise to wait for your call to be done :
prom = new Promise((resolve, reject) => {
$.getJSON('http://api.open-notify.org/astros.json', function(){
astronautsData = data;
resolve('Ajax done');
});
});
prom.then((successMessage) => {
console.log(successMessage);
alert(astronautsData.people[0].name)
});
Exposing variables in window/global scope is bad in my opinion. You should wrap it in a function (like a class of sorts) and expose it like this:
function Values(type) {
this.value1 = "something";
}
From this point you can use prototype to define additional functions on "Values" like so:
Values.prototype.doStuff = function() {
return this.value1 + ' addsomething';
};
Inside of the prototype function you can define/return promises or do whatever you want including assigning values to the instance. You can also assign the instance to a global variable to make it a singleton of sorts. Granted your still using a global variable for that but its the instance of Values assigned to the variable not the actual values that are stored.
This is a bit of an over simplification perhaps, but in a way this is how the global variables for lodash or jquery work, although they have a LOT more going on to check for existing global variables and such before attempting to define it on global scope as typically you want to avoid that.
you can use var at global scope (outside of all functions) to declare a global variable:
<script>
var astronautsData;
$(function(){
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
</script>
use global.astronautsData if you want it to be global
Related
I've a question about subsequent function calls or somehow. I've this code here:
let socket = new WebSocket("localhost:8181");
socket.subscribe("abc").bind("test", function (response) {
console.log(response);
});
subscribe(channel) {
//Here I do some things
return this;
}
bind(eventName, callback) {
//Here I need the "abc" value
}
Currently I'm calling a second function after another to first subscribe something and then bind it. The problem is that I need the value passed to the subscribe function in the following bind function.
Currently I'm returning this because otherwise .bind() would be undefined because of the scope bla bla so because of this I can't just return the channel. Does someone has an idea how I can get this done without changing the function call structure?
You can't return this and also pass a variable. I think your best bet may be wrap your subscribe call in a closure so that you can keep local state.
function createAndSubscribe(abc) {
// You can create other local variables here
let otherLocal = 'foo';
let socket = new WebSocket("localhost:8181");
socket.subscribe(abc).bind("test", function (response) {
// Use abc or foo here
});
}
createAndSubscribe('abc');
Every time you call the function createAndSubscribe, it creates a unique closure that holds the value of abc and any other variables that you create.
i want to pass value to chrome.storage.sync.get() function.
chrome.storage.sync.get('privateKey', function(data, e) {
if (data.privateKey) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var uncrypted = decrypt.decrypt(e.detail.encryptedVal)
alert(uncrypted);
} else {
alert("key is not set");
}
});
but e.detail.encryptedVal is showing me as undefined.
The callback of .get() expects exactly 1 parameter.
By passing a function that takes 2 parameters (i.e. function(data, e) {...}), you do the following:
The function is called with one parameter. It is assigned to a callback-local variable data.
The second parameter stays undefined. It is assigned to a callback-local variable e.
If there was a variable e in the outer scope, it is no longer accessible.
I assume the part 3 is exactly your problem. You had a variable e in the scope where you called .get(), but you made it inaccessible.
Generally, due to the concept called closures, you don't actually need to pass e inside the scope - you just use the variable from the outer scope, and it will be retained in memory until the function executes. Think of it as a "locally global" variable, if that makes any sense. If it doesn't, there are better explanations.
With that in mind:
chrome.storage.sync.get('privateKey', function(data) { // just don't mention e here
/* ... */
// Just use e inside if it comes from outer scope
var uncrypted = decrypt.decrypt(e.detail.encryptedVal);
/* ... */
});
Better yet, let's make that into a function:
function decryptValue(value, callback) {
chrome.storage.sync.get('privateKey', function(data) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var decrypted = decrypt.decrypt(value);
callback(decrypted);
}
}
/* ... */
decryptValue(e.detail.encryptedVal, function(decrypted) {
// Do something
});
/* ... */
Note that callback variable? While you can use decrypted inside the callback of .get(), due to the fact it's asynchronous you can't use it outside. There is a very good overview of the problem, and another one here. Basically, .get() is asynchronous so you HAVE to use a callback.
/* ... */
decryptValue(e.detail.encryptedVal, function(decrypted) {
// Do something with decrypted
});
// Here, decrypted is not yet computed
/* ... */
Most of Chrome API is asynchronous. I would recommend to read You Don't Know JS book on the topic.
So, from the comments bellow, I suppose you'd like to pass the value to get callback in order to user it in the callback. Unfortunately, this can't be done the way you want it to be done. But, what you can do is write a decrypt function that will take the encryptedVal as an argument, and simply use it
function decrypt(encryptedVal) {
chrome.storage.sync.get('privateKey', function (data) {
if (data.privateKey) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var uncrypted = decrypt.decrypt(encryptedVal)
alert(uncrypted);
} else {
alert("key is not set");
}
});
}
Do note that this function uses asynchronous code and you may not return from it as you'd expect.
I've tried this:
function a_function(){
var data = "information";
});
console.log(data);
You can't. You need to create a variable outside of that scope and assign to it:
var data;
function a_function(){
data = "information";
});
a_function();
console.log(data);
Another answer has been posted mentioning learning about scope. Follow that advice and try to get your head around it early, it will save you a lot of hassle in the future.
Technically you can, though it's generally not a good idea:
function a_function() {
data = "information";
}
a_function();
console.log(data);
The reason this works is because, by not using the var keyword to declare a variable, JavaScript (being the good little dynamic language that it is) is writing to the data property of the "current" object, which is window. And, thus, globally accessible. It's basically the equivalent of doing this:
function a_function() {
window['data'] = "information";
}
a_function();
console.log(window['data']);
As I said, it's generally not a good idea. Other approaches include returning the value:
function a_function() {
var data = "information";
return data;
}
var data = a_function();
console.log(data);
Or perhaps creating the value in the larger scope and setting it in the function:
var data;
function a_function() {
data = "information";
}
a_function();
console.log(data);
Basically, in general you want to maintain scope and control flow and try to avoid "globals" where possible.
you need to read about scope and how it work .
http://www.w3schools.com/js/js_scope.asp
https://en.wikipedia.org/wiki/Scope_%28computer_science%29#JavaScript
For example a variable declared in a function exist only in this function. Once you are outside this fonction, the variable are deleted so it is undefined
You either have to pass the value to a variable in the scope that is shared by the console.log() call like:
var data;
function a_function(){
//note the ommission of the 'var' keyword
data = "information";
});
a_function();
console.log(data);
or you have to have the function return the value and use that as input to the log() method:
function a_function(){
var data = "information";
return data;
}
console.log(a_function());
or wrap the console.log() call in a helper function that your function calls from within its scope, passing data as an argument:
function log(data){
console.log(data);
}
function a_function(){
var data = "information";
log(data);
}
EDIT: as others have mentioned, while we can tell you all the ways to do this, it is better to learn more about scope and understand why the methods people suggest work.
If you want to ecapsulate data but use it outside of the function a_function, you need to return data and call a_function. Something like this should work:
function a_function() {
var data = "information";
return data;
};
var data = a_function();
Note, due to scope, data inside the function is different than data outside the function. If you don't create a new var named data outside the function, you will not be able to access data because it doesn't exist in the outer scope.
The following code demonstrates scope:
function a_function() {
var data = "information";
return data;
};
var data = "different information";
var data2 = a_function();
console.log(data);
console.log(data2);
The output from the code will yield:
different information
information
I'm trying to call a js function within another one, but use the argument to specify the function. ie depending on the argument passed, it will call a different function
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
check+n();
}
else
}
So, for example, if the argument 'Balloons' was passed as n, then it will call the function checkBalloons(). "check+n();" is not currently working here. Sorry for my lack of simple js syntax!
If the function is defined in the global scope (browser) you can do:
window["check"+n]();
or some tenants like Node.js you would access it from global object.
global["check"+n]();
if it is a part of some other object then you would do the same.
obj["check"+n]();
Functions and properties defined on an object can be accessed using [] convention as well. i.e obj["propFuncName"] will give you reference to it, so in case of methods you add () to invoke it.
If the function is global, you would do this:
window["check" + n]();
or, you could put your function in an object like so:
myNamespace = {};
myNamespace.checkSomething = function(){ /* ... */ }
// call it like this:
myNamespace["check" + n]();
The answers thus far are correct, but lack explanation.
In JavaScript, you cannot call a function by name when that name is a string. What you can do is retrieve a value from an object by name, and if that value happens to be a function, you can then call it. For example:
var myObject = {};
myObject.myFunction = function() { alert('test!'); };
// Get the property on `myObject` called `myFunction`
var theFunctionLookup = myObject['myFunction'];
// Since that property was a function, you can call it!
theFunctionLookup();
In the browser, functions that are defined in the global scope are attached to the window object. For example, this works:
function myFunction() { alert('test'); }
var theFunctionLookup = window['myFunction'];
theFunctionLookup();
You can shorten the last two lines into one:
function myFunction() { alert('test'); }
// Look up and call the function in one line.
window['myFunction']();
For the same reasons, you can use a dynamically-calculated string to look up functions.
function checkBalloon() {
alert('checking balloon');
}
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
window['check' + n]();
check+n();
}
}
toggle('Balloon');
if you do this way:
if (sessionStorage['toggle'+n]== 0){
window["check" + n]();
}
will work
I am having some trouble with the classic javascript local variable scope topic, but dealing with a JSON variable. I have looked at other questions here regarding the same thing, but nothing has matched my case exactly, so here goes. I have a class that I have made from javascript that has 3 methods: func1, func2, and func3. I also have a local JSON variable that is being set in one of the methods from an ajax call I am making with jquery, but is not set when I call a method that returns that local variables value. I know the ajax is working fine, b/c I can display the data that is being returned and being set to the json variable fine with no problem. It is only happening when I call another method that interacts with that JSON variable. Here is a basic version of my code:
function func1(){
func2();
}
function func2(){
$.getJSON("http://webservice.mydomain.com/methodname&jsoncallback=?",
function(data){
this.z = eval("(" + data.d + ")");
alert(data.d); //this displays the data!
alert(this.z.ArrayProperty[0].Property1); //this displays
//the correct data too!
}
);
}
function func3(){
return this.z.ArrayProperty[0].Property1;
}
function myClass(var1, var2){
this.x = var1;
this.y = var2;
this.z = "";
this.func1 = func1;
this.func2 = func2;
this.func3 = func3;
}
And then in my .html page, I am having the following code:
var obj = new myClass(1,2);
obj.func1("abc");
alert(obj.func3()); //ERROR: this.z.ArrayProperty is undefined
Any ideas?!?! I am racking my mind!
Thanks
I don't think this is anything to do with scope.
Remember that the AJAX call is asynchronous so func3 is being called before the JSON has been returned and your anonymous function has had a chance to set this.z to anything.
I don't think "this" inside your callback is the same "this" that defined func2. Using the Prototype JavaScript library, you can use bind() to get around this.
You may be able to just add a new variable in func2, or use a bind function in whatever library you are using.
func2() {
var me = this;
$.getJSON("http://webservice.mydomain.com/methodname&jsoncallback=?",
function(data){
me.z = eval("(" + data.d + ")");
success = true;
alert(data.d); //this displays the data!
alert(this.z.ArrayProperty[0].Property1);
}
);
}
I could be completely wrong, but it look like the "this" variable is messing you up. "this" variable depends on how you call the function. It looks like you really don't want to be using that. Instead, I use:
func2() {
var that = this;
Then later in the code use:
function(data){
that.z = eval...