1

Ever since beginning JS a bit over a year ago, I've always had issues with variables that I declare inside of functions but want to access outside the functions. Initially, I would use a script element above all my other scripts with every variable I wanted declared with a var x,y,z;, or a window.x = __; if I didn't want to add it to a list like that. That got annoying to keep up with, so when I learned about not using var to declare things, but still being able to access them, I began to do that. Now I'm seeing things like this, which say to use var for all variables for various reasons. Would it be possible to create an object the variables bubble up to instead of window if there are no previous declarations of the variable, or a substitute for the var declaration? I have the idea to do something like

window.NewVarList = [];
//or is  « var NewVarList = []; »  more appropriate?

function gvar(NewVar,SetVal){
    window.NewVarList[NewVar] = SetVal;
    //or  « NewVarList[NewVar] = SetVal; »
}

but don't know how to make a variable instantly be searched for in NewVarList(using VarInList rather than NewVarList['VarInList']) or how to make gvar x = __; instantly call a gvar(x,__) with the right types for the value I want to set to, instead of everything being a string. Would it be possible to make all variables declared without var instantly go to the window.NewVarList and search for them without needing a NewVarList[VarName]? And if I can't have things instantly bubble up to NewVarList, can I make gvar work without needing the normal parenthesis and arguments? Or should I just go back to defining all my variables outside of my functions? Would it be safe to continue to just leave the var declaration out of my code?

Duhuhk
  • 13
  • 2
  • If you're using named indexes instead of numbers, it should be an object, not an array. `window.NewVarList = {}`. – Barmar Apr 23 '19 at 00:47
  • I don't think there's any way to make some other object be the default container of undeclared variables. – Barmar Apr 23 '19 at 00:48
  • See https://stackoverflow.com/questions/54776759/how-to-avoid-accidentally-implicitly-referring-to-properties-on-the-global-objec - I think there is no clean way to avoid the implicit `with(window)` that all scripts are essentially surrounded with. But you should be trying to *avoid* such implicit assignments - they make code harder to reason about. I suppose you *could* send script text to a worker, so that it gets assigned to the worker's global scope, rather than the original window's, but that isn't all that much of a help – CertainPerformance Apr 23 '19 at 00:51
  • It would be better not to use `var` at all, and use `const` (or `let`, when required) instead, which do not implicitly assign themselves to anything, which is arguably a good thing – CertainPerformance Apr 23 '19 at 00:53

1 Answers1

0

A simpler solution is to put all your code in an IIFE.

;function() {
    // all your code goes here
    var x, y, z;

    function foo() { ... }
    function bar() { ... }
    ...

}();

Variables you declare at the top-level of the IIFE can be used as global variables in all the other functions, but they won't become part of the window object.

The only caveat is that none of the functions defined here become global variables, either, so you can't use them in things like onclick="foo()". That shouldn't be a serious problem, since coding like that is considered poor style these days. But if you want to be able to do that, you can define the function like this:

window.foo = function() { ... };

If you need a number of global names, you should collect them into a single object and put that in window; using a single object avoids polluting the global namespace, which might run into collisions with other libraries that you load (you can see this approach in libraries like jQuery, underscore.js, and lodash).

In general, when you want to create something to hold named items, you should use an object (or an ES6 Map). While any type of data can be given properties, this is the express purpose of objects.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • The main reason I'm having this problem is accessing variables not just in other functions, but functions in other files. Would this still work for sharing variables across different files, or would the global part apply only to what is in the specific file since the IIFE would only be in that one file? – Duhuhk Apr 23 '19 at 14:19
  • Anything that needs to be accessed across files needs to be a real global variable, i.e. in `window`. The IIFE defines a local scope that can't be accessed from outside. Your idea of creating a single global variable containing all your properties is the best way to go then. But it should be an object, not an array. – Barmar Apr 23 '19 at 15:45
  • Is there a specific reason that it should be an object, not array? I thought that objects can have properties reached the same way arrays can, and vice-versa. I think I'll be going with this `window._` solution for holding everything either way, just looking for clarification on why it should be an object. – Duhuhk Apr 24 '19 at 14:41
  • Any type can have properties, but objects are used specifically for this. If you print other types, the properties aren't shown. If you do `console.log(someArray)` all you see are the array elements, not the properties. – Barmar Apr 24 '19 at 14:43
  • I see now. Thanks! Do you want to add this to the initial answer so I can mark it as the right one, or can I copy-paste the comments here into it? I think I'm definitely gonna be using this in the future, so want to give credit where it's due – Duhuhk Apr 26 '19 at 13:26