Is there a way to disable Global Variable Declaration within Function - javascript

I ran into a issue eventually it turned out because I did not use var prefix during declare a local variable within a function, so when it get to next function it actually automatically pick it up the variable, even though that was a syntax mistake as my initial intent is to use another local variable with similar name. So is there a setting on google apps script to throw error on a global variable declaration within function to avoid this kind of tricky issues?
Here is sample code of my problematic issue
function f1(){
for(var idx=0;idx<length; idx++){
tmp1 = idx; // since tmp1 missing var, it endup as global variable
...
}
}
function f2(){
Logger.log(tmp1);// even though I did not delcare tmp1 here, it will not throw either validation nor runtime error.
}

Use the JavaScript strict mode. To do this, add the following at the global scope:
'use strict';
The above string literal could be added on any file in your Google Apps Script project, just be sure to add it outside of any function. In order to make this easier to find, add it on top of your project's first file.
Resources
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
Related
Enforcing strict mode in google-apps-script files using Chrome on Chromebook

Related

Can we change the execution context of the browser's JavaScript from Window object to something else?

Assume I have a legacy file called module.js which is like this:
a=1;
This by default attaches to the window object polluting the global (actually window) scope when you execute it in the browser.
Is it possible for me to attach it to a different object instead without changing the contents of the source code?
Since the only real problem is the execution context and nothing else, an ideal solution would be something like this:
change execution context from window to module object;
execute the code;
change execution context from module to window object;
If this is not possible, adding wrappers (like IIFE) to the source code is fine as long as the inner contents are not changed. Changing the inner contents needs a full scan of the code which is expensive.
I can, for example, wrap it into a function like this (✓):
function module()
{
a=1;
}
If it is executed in strict mode, I can avoid global scope pollution. However, I can't get hold of the object.
I don't want to do something like this (✗):
module = function module()
{
return a=1;
}
because we need to add return wherever there is an assignment and that means scanning the entire code.
I am just trying to see ways to improve legacy code meant for the browser with minimal effort.
The answer to the first question, no it is not possible to change the default execution context in the browser. window is a special variable and assigning anything else to it will not change default execution context. See Global Object in MDN. And here is an illustration
(function() {
window = {}
a = 5 // leaking declaration
var b = 10
})()
console.log(a) // a is on global scope
//console.log(b) // exception b is not defined in this scope
var b = 5
window = new Object()
window.c = 5
console.log(window.b) // 5
console.log(c) // 5
The answer to the second part about how to work with legacy code, there are many tools which do AST transformation and depending on your goal you should probably use one or more of them.
jscodeshift allows you to write codemods which are functions that receive code and apply transformations to it. This is probably the most powerful tool in this category.
ESLint allows you to set rules (for example no global vars) and have a --fix option which will apply automatic fixes in some cases like changing from single quote to double quotes (this is mostly for style related rules).
prettier is a code formatter only concerned with code appearance: indentation, spaces etc.
AST Explorer an online tool that lets you see the internals of all the above tools very useful to understand how it works and try code on small examples.

Newly defined variable reporting "undefined" in functions while the rest are not?

I've had a problem where some of my declared and defined variables have been reported as undeclared when it's time to use them inside a function.
So I've been playing about with it, and it seem like no - whenever I add anymore new variables, they are defined straight after they are defined in code, then inside function blocks they indeed reported undefined.
I have been using resources and not been releasing them, like URL objects and connections to databases, and so wonder if it's because I run out of memory?
So I rebooted my phone - no go. Besides, the older variables defined beneath the newer variable are reporting that they are indeed defined? while the new variable still arn't.
For more clarification, here's what visual studio is reporting:
^Every one of those variable in that block work correctly except for 'newVar' and any other newly defined variables
(disclaimer: I'm not a professional - only a hobbyist, and any code shown does not represent production ready code, thank you!)
Example issue code:
(function() {
"use strict";
var variable1,
variable3 = 10,
variable2 = 100,
function clickHandler() {
console.log(variable1); //prints "undefined" in green text.
console.log(variable2); //prints "100"
console.log(variable3); //prints "'variable3' is undefined" in red text
}
clickHandler();
})();
Developing a Windows Phone 8.1 app using latest public SDK, writing in javascript on Windows 10, inside Visual Studio 2015 community edition.
In reference to my comment, I'll take your response as a "no", the suggested example output is not what you'd get if you actually ran that code - I'll explain why I ask...
What you are referring to is called lexical scoping and it's a core concept - you can reliably access outer variables in a function closure and indeed your example runs without issue - at least on the V8 engine, I'm not in a position to test in a Microsoft flavoured environment right now.
The only notable observation that you could make from it (aside from the typo) would be the use of a function as a statement rather than an expression. See this post on the differences between the two - I've not spent any length of time investigating but it's conceivable that Javascript hoisting order could have quirky behavioural differences across different Javascript engines.
This is probably a red herring though because you'd expect all variables to appear as undefined in such cases - it's easy to verify if this is your issue however by simply swapping out the function declaration:
function clickHandler(){ // ... swap this function statement
var clickHandler = function(){ // ... for this function expression
Now onto what I suspect is actually the problem. I can't see the onPinch function in it's entirety on your screenshot but from what I can see there is no reference to newVar inside of it. The error in your console was not produced by your code but by your attempt to inject a reference to the variable via the debugger, into the execution context after it had been resolved.
When your code is running, the compiler won't just dump everything that was in lexical scope into the local context - it's going to make optimisations, i.e. you can't stick a break-point inside the function and expect to see a parameter that isn't used by the function in your actual code.
If you want to to play around with that variable in the console, make an arbitrary reference to it somewhere - for example, even the following will ensure it's in scope:
function onPinch(ev){
newVar;
//...
}
In your example the var line needs to be terminated with a ;
var variable1,
variable3 = 10,
variable2 = 100;
variable1 will then be the only undefined variable in the clickHandler function.

How do I prevent accidental global name space pollution with javascript eval?

I am writing a simple REPL (Read, Evaluate, Print, Loop) implementation in JavaScript. I am able to isolate code and calling context like so:
var sandbox = {
// Allow the input code to use predefined helper functions
// without the preceding use of the this keyword.
helper_fn: function() { alert("foo"); }
};
var func = new Function("with (this) { " + user_inputed_code + " }");
func.call(sandbox);
Now it closes the user_inputed_code so that this referers to sandbox and if the inputted code accesses or mutates this it is affecting sandbox.
However, I noticed that if the imputed code were to accidentally forget to preface a variable assignment with the keyword var that the global namespace get polluted.
Is there anyway to prevent this? If so how (maybe a regexp?)? Is there a better way to approach this?
I'm going to provide two completely different approaches from what others discussed here. They are both drastic, and are useful when you want to relatively isolate your environment.
The easiest technique that works in all browsers is to probably create an iframe, and append script tags to it. (Note, a really overzealous iframe can still get past that if they're in the same domain, at least in older browsers). I discuss that in this question.
Use web Workers, which have an isolated environment by default and have no access to the global object of the main execution thread. I discuss that in this question.
More specifically, if you're building a REPL take a look at this answer where we discuss and I explain how to eval code in the same scope but outside the global scope, using the first approach of iframes.
(I assumed a browser, in node you can simple use the vm module and select the context in runInContext)
Turns out there is a way with "use strict" and without Object.freeze. You have to manually replace the global namespace with your own sandbox object:
var sandbox, module, func, output;
// Empty object or with defined methods / properties
// you want to expose as globals.
sandbox = {};
// A reference to an object you WANT to provide safe
// access to. In this example it's just an empty object.
module = {};
// A better version of eval:
func = new Function("module", "with(this){return(function(module,global,window){\"use strict\";return eval(\"" + code + "\");})(module,this,this)}");
output = func.call(sandbox, module);
This code allows global and window to refer to a sandboxed object instead of the global name space. It masquerades the variables global and window as the sandbox object and the use of "use strict" will cause it to throw an exception if the input missed the use of var. It also wraps the function in a with statement to make the methods and properties defined in the sandbox object to work as if they were preceded by this.. To see an implementation example (with test specs) check out this gist.
Thank you all for your ideas. Hope this answer helps others.

Javascript: Variables being leaked into the global scope (Firefox addon)

I submitted my addon to the AMO direcotry and the editor came back with this:
There are still a number of variables being leaked to the global scope,
probably because you're using them undeclared like...
He did not mention all the problem variables, is there anyway to know which are in global scope / getting leaked?
I have a crapload of variables and it would take ages going through each one of them to make sure they were declared properly with a "var".
Please help!
Thanks!
If you're trying to track down variables that may have been implicitly declared as global because of the omission of var, you could run the code in strict mode. This will give you a ReferenceError if you try to use variables that haven't been property declared.
(function() {
"use strict"; // <-- this runs code inside this function in strict mode
// your code...
test = 'tester'; // gives a ReferenceError
})();
You'll need to run it in a supported browser, like Firefox 4 or higher. The "use strict"; declarative will ensure that any code inside the function will be evaluated using the rules of strict mode.
Besides properly using the var keyword, you should make sure all your javascript is wrappend in a function like this:
(function(){
//Your code
}());
This keeps all your variables within the scope of an immediately invoked function.
Use firefox with firebug, add a break point somewhere appropriate and watch the "window" object, all the variables within the global scope are a member of it.

Have Firebug break when a global variable x is defined

We have a very large JavaScript application, where after many months of coding there have inevitably sprung a couple scope slip ups where a variable is defined without using the var keyword in the following fashion:
function() {
x = 5; ...
}
instead of:
function() {
var x = 5; ...
}
This is happening somewhere - we're not sure where - and searching for the variable name in question is difficult, since it's a common word that appears 1000s of times in our source.
Is there a way to ask Firebug to break on the line that first creates a given global variable? To clarify, I would like to break at exactly the instant when window.x switches from undefined to a defined value, and to break statement.
I've tried creating a watch expression and hoped I could turn it into a breakpoint, but I can't seem to create watch expressions without some kind of context or scope.
If this isn't possible with Firebug, I'd be interested in anything that can accomplish this in Firefox in general.
Provided a few things
You know the name of the variable
You don't have a variable with that name in the global scope (declared outside functions), but only inside functions.
There are calls to the function that declares the variable.
this little script would do the trick:
<script type="text/javascript">
window.__defineSetter__("x", function(value) { console.trace(); });
x = 1;
</script>
You'll get a trace of the executed code before that assignment.
It may fail to report some situations, so take a look at JSLint. Load all your JS files right there and lint them.
Here's another solution that only works in Firefox because it uses the Firefox-specific watch method.
Put this piece of Javascript at the very top of your html page, just after the <head> tag:
<script>
window.watch('x', function() { debugger });
</script>
Note that watch works on any Javascript object (window is the global Javascript object).
Here's the solution I ended up using by modifying Ionut G. Stan's solution:
window.__defineSetter__("name", function(value) {
if (value=="div") {
debugger;
}
});
I used debugger instead of console.trace(), so I could stop and look at it mid-execution. With console.trace() I got a bazillion trace statements due to this line executing many times.
The leaky scope turned out to be buried in Dojo, where Dojo is setting that variable to the name of a processed element.
View your web page on the SeaMonkey browser (I use version 1.1.16) and look at the error console, you will see a message of this type for each assignment to an undeclared variable :
Warning: assignment to undeclared variable x
Source File: http://....js
Line: ##
In addition to debugging, I would advise to check your code with JSLint, which reports unexpected assignments in the global scope as errors.
There are several command-line bundles of jslint, such as jslint4java which can be used cross-platform in Ant build scripts.

Categories

Resources