0

How to detect added global variables at runtime between two lines of code ?

I want to be able to tell what variable was added in between two lines of code at runtime without analyzing the source code. Just 1 variable is added.

Example:

"use strict";
//start

const myVariable = "10"; //detect this new variable

//end

const newVariableAdded = detectWhatIsNew();

// newVariableAdded should be "10" or "myVariable"

What I tried so far:

"use strict";

const notNew = Object.getOwnPropertyNames(window);

const detectWhatIsNew = function () {
    let newString;

    let key;
    Object.getOwnPropertyNames(window).some(function (key) {
        if (!notNew.includes(key)) {
            notNew.push(key);
            newString = key;
            return true;
        }
    });
    return newString;
};


//start    

const myVariable = "10"; //detect this new variable

//end

const newVariableAdded = detectWhatIsNew();

// newVariableAdded should be "10" or "myVariable"
K Scandrett
  • 16,390
  • 4
  • 40
  • 65
Walle Cyril
  • 3,087
  • 4
  • 23
  • 55
  • 1
    [Possible XY-Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem): what do you want to do actually? How do you expect a variable to be added during runtime? Please show an example how the new variable, `myVariable` in your example, is being added to the source while the program is running. – try-catch-finally Nov 20 '16 at 18:48
  • `detectWhatIsNew()` since when? Since the last call to that function? Since the last line before that function (which is actually whitespace)? – Bergi Nov 20 '16 at 19:11
  • For why your code cannot work, have a look at [Do let statements create properties on the global object?](http://stackoverflow.com/q/28776079/1048572) – Bergi Nov 20 '16 at 19:14
  • @Bergi Everyone here is saying that using `var` instead of `const` or `let` would solve the problem, but not (I know `const` and `let` declares variables locally independently of the scope). Variables declared with `var` are declared before the execution of that variable declaration, so what you can do is to set a new property on the global object, being this property the new variable (it has to be new, independently of `undefined`). Comprove it by running this: `(_ => { "use strict", a = "10"; var a })()`. It won't throw any exception. –  Nov 20 '16 at 23:32
  • My bad, I was saying that your code was incorrect because you was returning only one info, but it's correct, I forgot to apply the edits about that in my answer –  Nov 21 '16 at 13:32
  • @FREEZE All I said is that you cannot detect `let`/`const` variables by inspecting `window`. Yes, hoisting is a problem for all variables; the global property is created right before a script is evaluated. But it's really unclear what the OP wants/needs anyway. – Bergi Nov 21 '16 at 15:57

3 Answers3

0

const and let are block-scoped, they don't create properties on the global object, but it's accessible by all code running within your enviroment (if declared outside a block, in the top level).

Your code only works for var or if you don't use any statement.

I don't think there's some approach that can do what you want.

Edmundo Santos
  • 8,006
  • 3
  • 28
  • 38
0

What @EdmundoRodrigues says is almost correct, except that it works for var (IT DOESN'T in this case, but it works for inexistent global property assignment... "set", independently of undefined.

You can't detect the case of a variable (using var declaration) being added by var too, because the var statement declares variables instantly (sorry if my terms doesn't fit, English isn't my primary language), e.g.:

(_ => {
    a = "10"
    var a
    alert(self.a) // undefined on window (global object)
    // So the variable a can be assigned and used before the var
    // keyword comes.
    // If var [a] were not declared here, a would be global, or
    // if it was strict mode, an exception would have been
    // thrown.
}) ()

It's like this for var, except for let and const:

( _ => {
    a = "10" // Uncaught ReferenceError: a is not defined(…)
    let a
})()

Your function will only count global var statement used in next-separate scripts to be executed yet, and will also count fine any global object properties that were not existent earlier in the current executing expression/statement, independently of the undefined value.

const and let will be only visible in the entire scope until their declaration are executed, unlike var. And as @EdmundoRodrigues says, let and const variables are visible locally only, independently of the scope (even when the scope is global).

# Checking your code (note: I made a change to detectWhatIsNew to return all recent variables and declared myVariable with var).

"use strict"

const detectWhatIsNew = _ =>
    Object.getOwnPropertyNames(self).filter(key =>
       !notNew.includes(key) && notNew.push(key))

const notNew = Object.getOwnPropertyNames(self)
var myVariable
console.log(detectWhatIsNew()) // an empty array

This won't work for var, but it does make sense! Because the presence of var is instant, the Object.getOwnPropertyNames(self) call would have captured this "a" in any position.

console.log(notNew.indexOf( "myVariable")) // bigger than -1

But your function will still work for different ways of setting global variables, like:

self.myVariable2 = "19"
console.log(detectWhatIsNew()) // Array { "0": "myVariable2" }
0

One way is to use the var statement and split the code into multiple files so that the var statement does not get hoisted. There is a possibility to use a service worker to do split the files automatically.

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>

<script src="prepare.js"></script>
<script src="addVariable.js"></script>
<script src="detectNewVariable.js"></script>
</body>
</html>

prepare.js

"use strict";

const notNew = Object.getOwnPropertyNames(self);

const detectWhatIsNew = _ => {3
    /*returns an array*/
    return Object.getOwnPropertyNames(self).filter(key => {
        if (!notNew.includes(key)) {
            notNew.push(key)
            return true
        }
    });
};

addVariable.js

var myVariable = "10";

detectNewVariable.js

console.log(detectWhatIsNew()); // Array [ "myVariable" ]

Another way is to create globals using the window.variable = notation

Walle Cyril
  • 3,087
  • 4
  • 23
  • 55
  • "Service worker is a programmable network proxy, allowing you to control how network requests from your page are handled." see https://developers.google.com/web/fundamentals/getting-started/primers/service-workers – Walle Cyril Nov 20 '16 at 17:13