Custom javascript class and private variable scope issue - javascript

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...

Related

Javascript - self-executing functions : why to use them if I can create local scope with not self-executing functions?

I know there are a lot of posts here and elsewhere about selfexecuting functions but I still have some questions after reading posts.
why would I ever assign a self-executing function to a variable? If seems that they execute themselves anyways.
var myFunc=(function() {
console.log('Hello World');
})();
I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!
(function() {
var name="my Name"
console.log(name);
})();
vs.
function() {
var name="my Name"
console.log(name);
};
//its the same
So I dont quite understand how self-executing functions are to keep local scope (as you can do that using not self-executing functions) so the only reason I see is to use them when you want to execute automatically for example on page load.
Thanks!
just one more question:
var test=(function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
})()
test.test1()
vs
var test=function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
}
test.test1()
--> what exactly happens here that because of IIFE I can actually execute test.test1() and not with a regular function?
You usually wrap your functions in a anonymous function when you want to keep your scope contained. This is also part of the module pattern which is still pretty popular:
https://toddmotto.com/mastering-the-module-pattern/
Then you can assign the outcome of that IIFE to a variable so your scope can only be accessed by calling that variable.
myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]
Your other function needs to be called manually and it also accessible from anywhere.
I suggest reading the article by Todd Moto it explains a lot.
If that IIFE doesn't return anything, then there's indeed absolutely no use to assign it to anything. Though there may of course be examples of IIFEs returning something you want to use later; in that case the IIFE is a private scope to set up some object for example:
var foo = (function () {
var bar = 'something';
// here be dragons
return baz;
})();
This gives you a private scope to assemble baz without unnecessarily leaking temporary variables into the global scope.
There's no difference in those examples, except that the second one doesn't execute and therefore never does anything. Scoping and the purpose for the scoping are unchanged.
First, briefly, these are not self-executing functions. (That would be a recursive function.) These are inline-invoked function expressions (IIFEs). The function doesn't call itself, the expression calls the function.
why would I ever assign a self-executing function to a variable?
That's not what that code does. It assigns the result of calling the IIFE to the variable. You'd use it when you want that result, for instance:
var x = (function() {
var n = 0;
return {
increment: function() { return ++n; }
};
})();
console.log(typeof x); // "object"
console.log(x.increment()); // 1
console.log(x.increment()); // 2
x doesn't receive the IIFE, it receives what that IIFE returns — in this case, an object with a function on it.
I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!
Yes, that's true. You use an IIFE when you only need to do what's inside the IIFE once. Otherwise, absolutely, you define the function, give it a name, and then reuse it wherever you need it. The variables inside the function are indeed private to it (unless exposed in some way), and are specific to each call to the function.
1: To assign an IIFE to a local Variable makes sense for something like that:
var getID = (function () {
var id = 0;
return function () { return id++; };
})();
This way you can get new IDs without running the risk to reset the internal counter from anywhere else in the code, except by redeclaring the variable.
2: Basically you create Scope by creating a function. But if you do not execute it, well, it doesn't do anything. So if you have that:
function () { return 'foo' };
How do you want to call it if it is not assigned to a variable or does not have a name? By itself it wont do anything, since it is not called. Something like that is dead code and can safely be removed.
your first thing has no sense whatsoever:
var myFunc = =(function() {
console.log('Hello World');
})();
myFunc is not a function and it is undefined.
The sense, as I see it, for a self executing function is to package some code that has to be executed right away.
var p1=1, p2=2, obj = {
prop: (function(x,y){ return x+y;})(p1, p2)
}
OR
avoiding overwriting already defined functions/objects in the case your script will be inserted in a already existing application and also creating a kind of private methods, if you like:
function aFunction() {
console.log('a code');
}
(function(w) {
function aFunction() {
console.log('b code');
}
w.run = function() {
aFunction();
};
})(window)
aFunction();
run();
You use self executing functions to expose only what you need out of a scope. I think I have a somewhat clear example:
let myObject = (function(){
let privateVariable = "I'm private";
function privateMethod() {
//private method
};
function methodToExpose() {
//this method I will expose
}
//what is returned here, is what is public
return {
PublicMethod: methodToExpose
//other public properties
}
}());
So, the function gets executed immediately, and what happens is I have an object that is defined by what I returned from the function.
Another example I could give you is to retain variables of the current scope inside a closure, but you wouldn't really use it that much, since we now have let. A practical example:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){ event.target.innerHTML = toPrint; })
}
</script>
When you click on a span, the value will be replaced with the value... "new: 4"!
That's because when you finished executing, that's the value that toPrint has. The function assigned to the click event retrieves that toPrint, and at the time it retrieves it, it is "new: 4". We solve this with closures:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){
var currPrint = toPrint;
return function(event){ event.target.innerHTML = currPrint ; };
}())
}
</script>
By using a self executing function, we save the current value of toPrint in the currPrint variable inside a local scope. When we later click on a span, the function assigned to the click even will use the variable currPrint, which contains the value that toPrint had at the time the function was assigned, not the value that toPrint has at finished execution.
Note that this is solved also by using let instead of var, but still, it's an example of self-executing functions :)
In the form of IIFE (or immediately invoked function expressions), they can then be used to create plugins or used as namespaces and attached to window / jquery / or other global level object for use later.
When you name a function like assigning anonymous function to a variable, you can use it later by calling the variable with parentheses, in your example, defined myFunc with
var myFunc=(function() {
console.log('Hello World');
});
Use it later in code as myFunc();
In your example, you are storing the output of function directly in variable, by calling it immediately, and there is no output to be stored.
So, if you later write console.log(myFunc);, there is undefined as output.
Better IIFE example from your code samples is the one mentioned below.
(function() {
var name="my Name"
console.log(name);
})();
It executes, does a console.log and that's it. Adds nothing to namespace or the global object in your case.
The last of your examples defines a function, does not execute it then, and since it does not have a named variable assigned, or a name, it gives syntax error and cannot be used later in code. So, below example is useless.
function() {
var name="my Name"
console.log(name);
};
You have added two more examples with var test = function myFunc. First one will work fine with test.test1(). For the second one, you need to evaluate test as a function first and then call its function, like test().test1().
I guess you miss something here. Just to make basic things clear - if you assign a self executed function to a variable the actual return value of the function when executed at this time is assigned to the variable and not the function itself.
var myFunc = (function() {
console.log('Hello World');
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === undefined
var myFunc = (function() {
console.log('Hello World');
return 'japp';
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === 'japp'
So why is this pattern around?
IIFEs are very useful to
limit the scope
if you declare
var test = 'test'; // var test actually will be assigned as a property of the current context (this)
window.test = 'test'; // so you pollute the global namespace which is not a good practice
so this would be mouch better
(function() {
var test = 'test';
})();
another very good thigs with IIFs is that you can achieve a design with "privates"
var myFunc;
(function() {
var i = 0; // i is available for myFunc with private access
myFunc = function() { console.log( ++i ) };
})();
myFunc(); // logs 1
myFunc(); // logs 2

how can I store my data in a global variable?

$(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

call a js function based on the argument passed

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

Retrieve variable from javascript object method callback

In my code I need to call an object method, retrieve the data from its callback, and pass it to another method or function.
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
However, the callback does not recognize any functions/objects/variables outside its scope.
What I've tried to do right now is wrap everything around a function.
var myData = '';
(function(myData) {
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
myData = data;
}
);
});
doAwesomeStuff(myData);
However that doesn't work either.
Anybody know how to properly accomplish this?
You haven't really given us enough to go on there, but this statement:
However, the callback does not recognize any functions/objects/variables outside its scope.
...is incorrect. A function has access to everything in scope where it's defined, so for instance:
var a = 10;
function foo(b) {
bar(5);
function bar(c) {
alert(a + b + c);
}
}
foo(12); // alerts "27"
Note how bar had access not only to c, but also to b (from the call to foo) and a (from the outermost scope shown).
So in your example, the anonymous function you're passing in as the callback has access to everything that's in scope where it's defined; doAwesomeStuff having been defined elsewhere presumably has access to different information, so you'll have to have the callback pass it any data it needs.
So I'm guessing your code looks something like this:
function doAwesomeStuff(data) {
// ...
}
function doSomethingNifty() {
var a = 10,
b = 20;
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
}
...and you want doAwesomeStuff to have access to a and b from the call to doSomethingNifty. If so, your only options are to pass them into it as arguments (probably best) or export them to variables some scope that doSomethingNifty and doAwesomeStuff share (probably not ideal, too much like globals).
You can bind required variables to the function passed into the async method.
Also, this SO question has a good treatment of the topic.
Your second version is not going to work at all, since you are trying to immediately access the data that are not yet available (not until the callback has been invoked.)
Your first method:
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
looks fine. Please provide more details on what is not working.
One problem could be that getSomeData() does not actually call the callback function.
doAwesomeStuff() can modify many different variables from the received data. The variables which can be accessed by doAwesomeStuff() are those that were available to it (in its scope) where it was created..

How do undefined or remove a javascript function?

I defined a global Javascript function:
function resizeDashBoardGridTable(gridID){
var table = document.getElementById('treegrid_'+gridID);
.....
}
After this function was used a few times, I want to remove(or undefined) this function because the Procedure code should be called again. if somebody try to call this method we need do nothing.
I don't way change this function right now.
so re-defined this function may be one way:
function resizeDashBoardGridTable(gridID){
empty,do nothing
}
Thanks. any better way?
Because you're declaring it globally, it's attached to the window object, so you just need to redefine the window function with that name.
window.resizeDashBoardGridTable = function() {
return false;
}
Alternately you could redefine it to any other value or even to null if you wanted, but at least by keeping it a function, it can still be "called" with no detriment.
Here's a live example of redefining the function. (thanks TJ)
An additional reason for pointing out that I'm redefining it on the window object is, for instance, if you have another object that has that function as one if its members, you could define it on the member in the same way:
var myObject = {};
myObject.myFunction = function(passed){ doSomething(passed); }
///
/// many lines of code later after using myObject.myFunction(values)
///
/// or defined in some other function _on_ myObject
///
myObject.myFunction = function(passed){}
It works the same either way, whether it's on the window object or some other object.
how about using a var?
// define it
var myFunction = function(a,b,c){
console.log('Version one: ' + [a,b,c].join(','));
}
myFunction('foo','bar','foobar'); // output: Version one: foo,bar,foobar
// remove it
myFunction = null;
try { myFunction(); console.log('myFunction exists'); }
catch (e) { console.log('myFunction does not exist'); }
// re-define it
myFunction = function(d,e,f){
console.log('Version two: ' + [d,e,f].join(','));
}
myFunction('foo','bar','foobar'); // output: Version two: foo,bar,foobar
OUTPUT:
[10:43:24.437] Version one: foo,bar,foobar
[10:43:24.439] myFunction does not exist
[10:43:24.440] Version two: foo,bar,foobar
The simplest approach is to set the function (treat it as a variable) to null. This works even if you don't declare it as a var. Verified this on IE.
resizeDashBoardGridTable = null
If the functions needs to be called 1 time you use an anonymous self invoking function like this:
(function test(){
console.log('yay i'm anonymous');
})();
If you have to call the function multiple times you store it into a var and set it to null when you're done.
Note: You don't have to name an anonymous function like I named it test. You can also use it like this:
(function(){
console.log('test');
})();
The reason I do name my anonymous functions is for extra readability.

Categories

Resources