Access a local variable from a function on the global scope - javascript

I have function a JSON/API loading callback function, where my var json = JSON.parse(response); is located that I use to read the JSON data:
// Call JSON File
function loadJSON(callback) {
xobj.overrideMimeType("application/json");
xobj.open('GET', 'pmApp.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
};
// Run loadJSON -
loadJSON(function (response) {
// Parse JSON string into object
var json = JSON.parse(response);
});
The var json is a local variable, and I would like to keep it that way (I don't want to make it global which would fix my issue), but I have a few functions that are called via HTML onChange events or on the global scope that need the json var to function correctly example:
//Global Scope
popBrandFields()
function popBrandFields(){
var brand_items = json.brands[0][client];
};
I cant cal popBrandFields(json) because the var json is not accessible due to being on a local scope. (I want to keep it this way due to security, puting it on the global scope fixes my issue but I want to keep it in the local scope.)
What would be the best way to achieve this?
I was thinking of returning the var json from the function it is defined in but I'm not sure how or if I can even set this type of function to a variable like in the following example:
function f(){
var foo = 100;
return foo;
}
var a = f();
Maybe there is a better way to load the JSON that can achieve what Im looking for if anyone knows of one?

You could ensure that all of the code that needs this value is in a SEF (self executing fuction).
It creates a scope inside the function where you can define all sorts of things, but does not pollute the global scope.
var globalVariable = 'bad'
(function(){
var json = 'not a global variable';
console.log('Your code goes here!');
})();

The solution I found was to create a function that held the rest of my code and vars, then I would call it from the loadJSON function passing in the json var so my new function can access it like so
loadJSON(function (response) {
// Parse JSON string into object
var json = JSON.parse(response);
jsonUsingFunction(json);
});
This way none of my vars are on the global scope.
Also instead of using onChangefrom the HTML I used event listeners which fixed my issue!

Related

Global variable accessed inside pre-defined function returns null - javascript

For some reason, I can't access a variable. Might be a scope issue, or timing issue, can't find it out. Here's my simplified code:
var endResult = "";
//function loads html into given element.Called as a callback later when google maps direction service is done//
function getResults(){
$.ajax({
url:'foo.php',
data: endResult,
//etc., response loaded asynchronously in div element//
});
}
//when form is submitted
$('#form').submit(function(){
var endResult = "";
//get form data, define variable//
$.post('bar.php',function(data){
var location = data;
//initialize Maps Directions Service//
var directionService = new google.maps.DirectionsService();
//function gets directions, and loads a single value into global variable "endResult"//
function calcRoute(){
var request = {//google maps arguments containing form data//};
directionsService.route(request, function(result, status) {
var endResult = JSON.stringify(result.routes[0].legs[0].distance.value);
console.log(endResult); //Outputs intended value from google maps//
//run function as a callback making sure that "endResult" is not null//
getResults(); //iside this function - value of "endResult" is null, data sent to foo.php is null//
});
}
calcRoute();
}
return false;
});
That's it, once I call getResults(), inside that function, endResult will be null. I'm sure it's something simple, but I can't get my head around it.
You're not assigning to the global variable, because you have
var endResult = "";
// ^^^
in the submit handler, and
var endResult = JSON.stringify(result.routes[0].legs[0].distance.value);
// ^^^
...in calcRoute.
Those declare local variables in those functions, which shadow the global (and the one in calcRoute shadows the one in the submit handler).
Just remove those vars, so you're assigning to the variable that code closes over (the global).
In general, avoid using truly global variables, and minimize the degree to which functions have side effects (like assigning to and reading from variables they close over). In this case, rather than having endResult be a global, there's no reason calcRoute can't pass it to getResults as an argument.
You should pass that variable in that function as an argument.
getResults(endResult);
You should avoid using var inside the form submit function. If you do so, it will be declared again as a local variable and will be limited to that function's scope.

Is it possible to get the local variable and parameter values with window.onerror

I have a simple javascript error logging mechanism in place and it looks somewhhat like this:
window.onerror = function (ErrorMsg, Url, LineNumber, Col, Error) {
// ajax these to the server, including Error.stack}
The problem is that I'd also like to get the value of the local variables and function parameters when the error occurred. Is this even possible?
I'm thinking about modifying the Function prototype so that each time a function runs, its arguments are stored in a global array of strings and then the error handler would just add this array to the ajax call. Can JavaScript do this?
#1 Can local scope be recovered in onerror() without black magic?
Without this being bound in the scope of window.onerror() or the surrounding variables being directly accessible, it's impossible to regain access to the variables you had set.
What you're mostly wanting access to is this.arguments or arguments or the equivalent, but that's destroyed. Any hope of obtaining a key-value associative array or hash-like object would involve meta-programming ( i.e. reading the function definition to obtain the variable names, and obtaining an exception report to attempt to salvage data ).
See this answer for more on something similar:
Getting All Variables In Scope
But this "lacking functionality" is a good thing:
If you could gain access to what you're asking for, that would likely be a fault in the Javascript engine. Why? Because the variable states and contents themselves are what caused the exception/error, assuming bad code wasn't the issue to begin with.
In other words, if you could get access to a faulty variable, that might be a door into an infinite loop:
Failure due to variable contents.
Error handler triggered.
Trace contents of variable.
Failure due to variable contents.
Error handler triggered.
Trace contents of variable.
Etc.
#2 Can Javascript store all arguments of every function call by voodoo?
Yes. It can. This is probably a really bad idea ( see #1 ) but it is possible. Here is a pointer on where to start:
Is there a way to wrap all JavaScript methods with a function?
From there, what you're wanting to do is push this.arguments or equivalent to a stack of function calls. But again, this is approaching insanity for many reasons. Not the least of which is the need to duplicate all the values, lest you reference mutated variables, or be unable to access the data at all... and like I said above, the problem of bad data in general. But still, it is possible.
Is this even possible?
No. A stack trace is proof that the stack has unwound, all stack frames and all the local variables they contained are gone. As for getting the name of a variable, that is not even possible at run time.
To start off i accept #Tomalak completely.
I was also put in your situation where i needed to debug a remote running app in case of crash.
As a work around I have forked my code for you in a fiddler. Please modify according to your need.
Caveat: You have to wrap the function body with try{..}catch(e){..} as illustrated in the fiddler code.
Please read the inline comments for understanding.
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
console.log(errorObj);
}
window.addEventListener("reportOnError", function(e){
console.log(e.detail);
/*Send to the server or any listeners for analysis.*/
//Http.send(e.detail);
});
function ExceptionReport(ex, args, scope) {
var self = {};
self.message = ex.message;
self.stack = ex.stack;
self.name = ex.name;
self.whoCalled = args.callee.caller.name == "" ? "Window": args.callee.caller.name;
self.errorInFunction = args.callee.name;
self.instanceOf = scope.constructor;
self.KeyPairValues = getParamNames(arguments.callee.caller.toString(), Array.prototype.slice.call(args)); //Contains the parameters value set during runtime
window.dispatchEvent(new CustomEvent('reportOnError', {'detail':self}));
}
//Utilties
function getParamNames(fnBody, values) {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,
ARGUMENT_NAMES = /([^\s,]+)/g,
result = fnBody.slice(fnBody.indexOf('(')+1, fnBody.indexOf(')')).match(ARGUMENT_NAMES),
obj={};
fnBody.replace(STRIP_COMMENTS, '');
if(result !== null){
for(var i=0; i < result.length; i++){
obj[result[i]] = values.length !==0 ? values[i] : null;
}
}else{
obj = null;
}
return obj;
}
/*
This is a testing/sample function that throws the error
*/
function testing(a,b,c){
try{
dummy(1,2) ; //This line throws the error as reference error.
}catch(e){
ExceptionReport(e, arguments, this);
}
}
//Class Emulation: For instanceof illustration.
function testingClass(){
this.testing = testing;
}
//Named self executing function: This calls the function
var myvar = (function myvar(){
testing(1,2,3);
})();
//Illustrating instanceof in exception
var myVar2 = new testingClass();
myVar2.testing(1,2,3);
//Calling from global scope this is Window
testing(1,2,3);
//Without variables
testing();
I have used examples to illustrate the behavior of functions called in different circumstances.
Below signifies the varialble used for
self.KeyPairValues : Used to store the function parameter set/passed during runtime
self.errorInFunction : This stores the name of the function error was caused in.
self.whoCalled : This stores the function name that invoked the defective function
self.instanceOf : This stores the name of the instance is called creating a new instance.
Other variables are same as in Error object
The others answers here are spot on, but I might be able to offer a suggestion for a slightly different way to accomplish this. Instead of trying to track all scope in your program, why not add a tagging function that tracks the scope of one function's parameters without affecting the runtime of the function. For for example:
var globalRecord = {};
function record(name, fn) {
return function () {
var args = [].slice.call(arguments);
var record = globalRecord[name] = {
args: args,
arg: {}
};
args.unshift(function (name, value) {
return record[name] = value;
});
fn.apply(args, arguments);
}
}
// Then, you track variables like this
var func = record("func", function (record, a, b, c) {
record("a", a); // named parameters are accessible now
record("b", b); // if some error occurs in the function body
return a + b + c;
});
// Calling func still behaves as before.
func(1, 2, 3);
// Errors handled like this:
window.onerror = function () {
globalRecord.func.args; // ==> last set of arguments past to function
globalRecord.func.arg.a; // specific arguments recorded with names
};
You could even use this method to track scope without using a function by anonymously calling the recorded function.
record("test", function (record) {
var a = record("a", /* whatever */);
var b = record("b", /* ... */ );
// do scope specific stuff that might fail
})();
Of course, this isn't a polished implementation by any stretch, but with a little work, I think you might be able to get the behavior you're looking for without any seriously black magic. By selectively adding and removing record calls as the need presents itself, you can have precise control over what is logged without any intrusive hacks.
You can find your answer in this link.
Before taking bundles from the server, you must modify them. For example, to solve your problem, you can do changes in the mentioned link as follows. In the BuildBundleContent Class make this change:
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}, this){1}",
errVariable, hasContent ? ";" : ""));
If in the modules you have to use something like:
var self = this;
You can use:
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}, self ? self : this){1}",
errVariable, hasContent ? ";" : ""));
And in added js file:
"use strict";
var customErrorLogging = function (ex, module) {
console.log(module);
//do something...
};
I hope help you.

Get caller instance from inside function

I currently have a few large files that I'd like to break up into smaller ones to ease editing. I feel as though these 'code snippets' wouldn't merit being created as a module and/or would have conflicts with scope if made as such.
So instead I'd perfer to just import the contents from these 'clipped' files, into the current execution scope and then eval them. Figured I'd write a helper function to do this(set in the global scope via the 'main' js file.) but I've ran into a snag.
Is there a way to get the calling instance from within the called function.
What I have so far:
global.acquire = (function() {
var cache = {};
var fileReader = require('fs');
return function (file, updateCache) {
var f = require.resolve(file);
if (f) {
if (cache.hasOwnProperty(f) && !updateCache) {
res = cache[f];
} else {
res = fileReader.readFileSync(f, {encoding: "utf8"});
}
cache[f] = res;
// Is there a way to get the calling function's instance so the eval will execute from the caller's scope?
return eval.apply(caller, '(' + res + ')');
} else {
throw "File not found";
}
}
}());
I know I could either pass the instance, or acquire.apply(), but that feels a bit sloppy if I can retrieve the instance from within the function.
There is no way to get at the caller's scope from within a separate function that is external to that scope without either passing in particular variables or using this to set data you want/need to access.

Javascript module pattern scope with this

I was developing using module pattern, and was wondering why I can't acces to the module scope using this. Maybe I'm wrong with the understanding of the revealing module pattern.
Here is the code I use :
var BLOG = window.BLOG || {};
BLOG.Module = (function(){
var
_this = this,
_hasLoaded = false;
function init(){
console.log(_this); // Logs the Window object
}
function _privateMethod(){
$.ajax({
url: 'lazyload/lazyload.html',
success : function( data ){
// _hasLoaded = true; // I want to access the variable in my module, How do I refer to it?
}
});
}
return {
init : init
};
})();
this is determined by how a function is called. If it's called directly, not through an object property (as your outer scoping function is), within that call this will be the global object in loose mode (undefined in strict mode). On browsers, that's the window object.
You wouldn't normally use this to try to refer to things within that outermost scoping function (for this reason).
If something did this:
BLOG.Module.init();
...then within the call to init, this (not _this) would refer to Module and you could refer to other properties on the object you create at the end of your outermost scoping function (there aren't any others currently, just init).
Re your edit:
var
_this = this,
_hasLoaded = false;
// ...
function _privateMethod(){
$.ajax({
url: 'lazyload/lazyload.html',
success : function( data ){
// _hasLoaded = true; // I want to access the variable in my module, How do I refer to it?
}
});
}
Just uncomment that line:
_hasLoaded = true;
This is because both _privateMethod and any ajax success handlers created as a result of calling _privateMethod are closures over the variables defined within your outermost scoping function. So you just refer to them directly.
If this use of the word "closure" is unfamiliar, don't worry, closures are not complicated.
Side note: This is an odd construct:
var BLOG = window.BLOG || {};
...as it mixes code requiring that it be at global scope with code that doesn't require that it be at global scope. It's entirely functional, it's just a bit odd. I'd probably go one way or the other:
// Requires that it's at global scope (and yes, this does work)
var BLOG = BLOG || {};
or
// Creates a global whether it's at global scope or not
window.BLOG = window.BLOG || {};

Is it possible to export a value of an variable from one javascript to an other?

I have made a Web page using jquery and php where all files are used in a modular style. Now I have two JavaScript files which must communicate with each other. One Script generates a variable (id_menu_bar) which contains a number. I want that this variable gets transported to the second JavaScript and is used there.
How do I make that?
Here the Script
menu_bar.js
$(document).ready(function() {
function wrapper_action(id_menu_bar) {
$(".wrapper").animate({height: "0px"});
$("#changer p").click(function() {
$(".wrapper").animate({height: "300px"});
});
}
$("#select_place li").live("click", function() {
var wrapper_id = $(".wrapper").attr("id");
var id_place = this.id;
if (wrapper_id != "place")
{
$("#select_level li").remove();
$("#select_building").load("menu_bar/menu_bar_building.php?placeitem="+id_place, function() {
$("#select_building li").click(function() {
var id_building = this.id;
if (wrapper_id != "building")
{
$("#select_level").load("menu_bar/menu_bar_level.php?buildingitem="+id_building, function() {
$("#select_level li").click(function() {
var id_level = this.id;
wrapper_action(id_level);
});
});
}
else if (wrapper_id == "building")
{wrapper_action(id_building);}
});
});
}
else if (wrapper_id == "place")
{wrapper_action(id_place);}
});
});
if the variable id_menu_bar is in global scope then it can be used by another script on the page.
jQuery's $.data() is also good for storing data against elements and means that you do not need to use a global variable and pollute the global namespace.
EDIT:
In response to your comment, there is a difference in how you declare variables that determines how they are scoped in JavaScript.
Global Variables
Outside of a function declaring a variable like
var myVariable;
or
myVariable;
will make no difference - both variables will have global scope. In fact, the second approach will give a variable global scope, even inside of a function. For example
function firstFunction() {
// Local scope i.e. scoped to firstFunction
var localVariable;
// Global scope i.e. available to all other JavaScript code running
// in the page
globalVariable = "I'm not really hiding";
}
function secondFunction() {
// I can access globalVariable here but only after
// firstFunction has been executed
alert(globalVariable); // alerts I'm not really hiding
}
The difference in this scenario is that the alert will fail and not show the value for globalVariable upon execution of secondFunction() until firstFunction() has been executed, since this is where the variable is declared. Had the variable been declared outside of any function, the alert would have succeeded and shown the value of globalVariable
Using jQuery.data()
Using this command, you can store data in a cache object for an element. I would recommend looking at the source to see how this achieved, but it is pretty neat. Consider
function firstFunction() {
$.data(document,"myVariable","I'm not really hiding");
globalVariable = "I'm not hiding";
}
function secondFunction() {
// alerts "I'm not really hiding" but only if firstFunction is executed before
// secondFunction
alert($.data(document, "myVariable"));
// alerts "I'm not hiding" but only if firstFunction is executed before
// secondFunction
alert(globalVariable);
}
in this scenario, a string value "I'm not really hiding" is stored against the document object using the key string myVariable in firstFunction. This value can then be retrieved from the cache object anywhere else in the script. Attempting to read a value from the cache object without having first set it will yield undefined.
Take a look at this Working Demo for more details.
For reasons not to use Global Variables, check out this article.
Does it have to ve a JavaScript variable?
Can you store the information using the .data() function against a relevant element?

Categories