24

Is there a way for javascript to detect all assigned variables? For example, if one js file creates a bunch of vars (globally scoped), can a subsequent file get all the vars without knowing what they're named and which might exist?

Thanks in advance :)

EDIT, Question Part 2:

How do I get the values of these variables? Here is what I have attempted:

This is what I ended up with, as per comment suggestions:

for (var name in this) {
    variables[name] = name;
    variables[name]=this[name]
}
3
  • I think you need variables[name]=this[name] there. Commented May 4, 2010 at 1:05
  • Thank you, I'm able to alert using the variable c using: alert(variables.c); Commented May 4, 2010 at 1:21
  • if you want to do this by parsing the code itself, here you go stackoverflow.com/a/75124307/10000823 Commented Apr 10, 2024 at 14:24

7 Answers 7

41

Flanagan's "JavaScript - The Definitive Guide" gives the following on page 653:

var variables = ""
for (var name in this)
    variables += name + "\n";
Sign up to request clarification or add additional context in comments.

6 Comments

Gives some extra stuff, presumably from the browser, but it works! Thanks :)
Uh. Sorry, but could you help me understand how to get the values of each of these variables now? I added code to what I attempted..
The "name" is like a key into a "this" hash. Get the value by this[name].
Thanks wombleton. I'd love to actually use the variables as a key / value hash itself. Is that what "this" is if used entirely by itself?
Matrym, say u have an object: var obj = {key1: 'val1', key2: 'val2'};. U can use that for loop and inside it have 'console.log('key is:', name, ' and val is:', this[name])'. Hope this helps
|
4

For Firefox, you can see the DOM tab -- easy, though not an answer to your question.

The for in loop provided in Kinopiko's answer will work, but not in IE. More is explained in the article linked below.

For IE, use the RuntimeObject.

if(this.RuntimeObject){
    void function() {
        var ro = RuntimeObject(),
            results = [],
            prop;
        for(prop in ro) {
            results.push(prop);
        }
        alert("leaked:\n" + results.join("\n"));
    }();
}

See also:

1 Comment

Hi Garrett. I've edited your answer to add code formatting to the RuntimeObject example.
1

There is the this variable. This is an object or an array, and you can simply put:

for(i in this) { //do something }

Unfortunately, it will return everything under the this object.

Comments

1

This will output all the variables into the console without needing to read the variable yourself.

var variables = ""
for (var name in this)
    variables += name + "\n";
console.log(variables)

/*
This could work too... but it's such a big unecessary code for something you could do in one line 
var split = variables.split("\n");
for (var i in split)
    console.log(split[i])
*/

Comments

0

If you want to assign values from one object to another, there are a couple of ways to do this:

//Way 1st
const variables= { ...this };
// or (I don't know what's the difference ;) )
// Don't forget const variables= {};
Object.assign(variables, this);
// Yes. It's very easy. You just "copy" entries from this to variables. I want to note that you are not copying a link to this, namely ENTRY.
Or
// Way 2nd. If u need to do smth. with entries.
const variables= [];
for (const name of Object.keys(this)) {
  /*
    Doing smth........
  */
  variables[name] = this[name];
}
I want to note that this is not a way to collect all declared variables into an object (I am looking for this method myself). They are simply ways of copying the contents of one object into another.

1 Comment

This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
0

Best method: this removes most unwanted-extra-browser variables, AND shows the value of each var

const browserVariables = ['value', 'window', 'self', 'document', 'name', 'location', 'customElements', 'history', 'locationbar', 'menubar', 'personalbar', 'scrollbars', 'statusbar', 'toolbar', 'status', 'closed', 'frames', 'length', 'top', 'opener', 'parent', 'frameElement', 'navigator', 'origin', 'external', 'screen', 'innerWidth', 'innerHeight', 'scrollX', 'pageXOffset', 'scrollY', 'pageYOffset', 'visualViewport', 'screenX', 'screenY', 'outerWidth', 'outerHeight', 'devicePixelRatio', 'clientInformation', 'screenLeft', 'screenTop', 'defaultStatus', 'defaultstatus', 'styleMedia', 'onsearch', 'isSecureContext', 'performance', 'onappinstalled', 'onbeforeinstallprompt', 'crypto', 'indexedDB', 'webkitStorageInfo', 'sessionStorage', 'localStorage', 'onbeforexrselect', 'onabort', 'onblur', 'oncancel', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'onclose', 'oncontextlost', 'oncontextmenu', 'oncontextrestored', 'oncuechange', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onfocus', 'onformdata', 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onloadeddata', 'onloadedmetadata', 'onloadstart', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onpause', 'onplay', 'onplaying', 'onprogress', 'onratechange', 'onreset', 'onresize', 'onscroll', 'onsecuritypolicyviolation', 'onseeked', 'onseeking', 'onselect', 'onslotchange', 'onstalled', 'onsubmit', 'onsuspend', 'ontimeupdate', 'ontoggle', 'onvolumechange', 'onwaiting', 'onwebkitanimationend', 'onwebkitanimationiteration', 'onwebkitanimationstart', 'onwebkittransitionend', 'onwheel', 'onauxclick', 'ongotpointercapture', 'onlostpointercapture', 'onpointerdown', 'onpointermove', 'onpointerup', 'onpointercancel', 'onpointerover', 'onpointerout', 'onpointerenter', 'onpointerleave', 'onselectstart', 'onselectionchange', 'onanimationend', 'onanimationiteration', 'onanimationstart', 'ontransitionrun', 'ontransitionstart', 'ontransitionend', 'ontransitioncancel', 'onafterprint', 'onbeforeprint', 'onbeforeunload', 'onhashchange', 'onlanguagechange', 'onmessage', 'onmessageerror', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate', 'onrejectionhandled', 'onstorage', 'onunhandledrejection', 'onunload', 'alert', 'atob', 'blur', 'btoa', 'cancelAnimationFrame', 'cancelIdleCallback', 'captureEvents', 'clearInterval', 'clearTimeout', 'close', 'confirm', 'createImageBitmap', 'fetch', 'find', 'focus', 'getComputedStyle', 'getSelection', 'matchMedia', 'moveBy', 'moveTo', 'open', 'postMessage', 'print', 'prompt', 'queueMicrotask', 'releaseEvents', 'reportError', 'requestAnimationFrame', 'requestIdleCallback', 'resizeBy', 'resizeTo', 'scroll', 'scrollBy', 'scrollTo', 'setInterval', 'setTimeout', 'stop', 'structuredClone', 'webkitCancelAnimationFrame', 'webkitRequestAnimationFrame', 'originAgentCluster', 'trustedTypes', 'navigation', 'speechSynthesis', 'onpointerrawupdate', 'crossOriginIsolated', 'scheduler', 'openDatabase', 'webkitRequestFileSystem', 'webkitResolveLocalFileSystemURL', 'chrome', 'caches', 'cookieStore', 'ondevicemotion', 'ondeviceorientation', 'ondeviceorientationabsolute', 'onbeforematch', 'getDigitalGoodsService', 'getScreenDetails', 'queryLocalFonts', 'showDirectoryPicker', 'showOpenFilePicker', 'showSaveFilePicker', 'variables', 'TEMPORARY', 'PERSISTENT', 'addEventListener', 'dispatchEvent', 'removeEventListener'];
var variables = '';
for (var name in this) {
    if (!browserVariables.includes(name)) {
        var value = eval(name);
        if (value != null && value != undefined && typeof value != 'function') variables += 'var '+name+' = '+value+'\n';
    }
}
console.log(variables);

1 Comment

Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' data: developers.google.com www.google.com www.gstatic.com".
-1

This one pretty prints all the variables, three layers deep. It may seem a little overkill, but using JSON.stringify() does not expand functions that returns an Object and instead displays [Object object]. You may want to async or call the function using a button, as it stalls on processing.

As I did not put anything to tell if it is an Object or Array, some {} are either Arrays or Functions. Maybe someone can refactor my script.

If you want it to print into a <div>, then you will need to change the spaces to &nbsp; and the newlines \n to </br>.

Notice it excludes window, document, self, frames, top, parent, jQuery, and $.

<textarea id="all-variables" readonly></textarea>

<script type="text/javascript">
(function() {
  function stringCheck(string) {
    return {
      window: true,
      document: true,
      self: true,
      frames: true,
      top: true,
      parent: true,
      jQuery: true,
      $: true
    }[string] || false
  }
  
  function printObject(o) {
    var output = '';
    for (var p in o) {
      output += '      '+ p + ': ' + o[p] + '\n';
    }
    return output;
  }

  const allVariables = document.getElementById('all-variables');

  for (var variable in this) {
    if (
      (
        (typeof this[variable] === 'object') || (typeof this[variable] === 'function')
      ) &&
      (this[variable] != (undefined || null)) &&
      (!stringCheck(variable))
    ) {
      allVariables.innerHTML += variable +': {\n';
      for (var secondVariable in this[variable]) {
        if (
          (
            (typeof this[variable][secondVariable] === 'object') || (typeof this[variable][secondVariable] === 'function')
          ) &&
          (this[variable][secondVariable] != (undefined || null))
        ) {
          allVariables.innerHTML += '  '+ secondVariable +': {\n';
          for (var thirdVariable in this[variable][secondVariable]) {
            if (
              (
                (typeof this[variable][secondVariable][thirdVariable] === 'object') || (typeof this[variable][secondVariable][thirdVariable] === 'function')
              ) &&
              (this[variable][secondVariable][thirdVariable] != (undefined || null))
            ) {
              if (this[variable][secondVariable][thirdVariable][0] != undefined) {
                allVariables.innerHTML += '    '+ thirdVariable +': {\n';
                for (var i = 0; i < this[variable][secondVariable][thirdVariable].length; i++) {
                  allVariables.innerHTML += printObject(this[variable][secondVariable][thirdVariable][i]);
                }
                allVariables.innerHTML += '    }\n';
              }
            } else {
              allVariables.innerHTML += '    '+ thirdVariable +': \''+ this[variable][secondVariable][thirdVariable] +'\'\n';
            }
          }
          allVariables.innerHTML += '  }\n';
        } else {
          allVariables.innerHTML += '  '+ secondVariable +': \''+ this[variable][secondVariable] +'\'\n';
        }
      }
      allVariables.innerHTML += '}\n';
    } else {
      allVariables.innerHTML += variable +
        (
          typeof this[variable] === 'string' ? ': \''+ this[variable].toString() +'\'' : ''
        ) +
      '\n';
    }
  }
})();
</script>

2 Comments

An IIFE? In 2023? Really? Is there a reason for that, or is it just for Ancient Knowledge show off? Second, we have the extended recursion with inordinate amounts of repeated code (obviously!). Third, since all of this is still not bad enough, you decide to top it off with a check for jQuery and $, because you're so used to having jQuery do your JS heavy lifting for you, you think it's built-in. Fourth, if you're drilling dow, INDENT the answer. HTML is your friend, although you don't seem to reciprocate. I'll have to do a full post later because this space is not enough to unpack all the BS.
Cool your jets mate, it's a basic example to serve a purpose and there are more things to worry about in life - I needed it for a device that runs ECMAScript v5 (the web browser uses NetFront based on WebKit stuck at year 2010). There is nothing wrong with using an IIFE, and in this case it encapsulates the functions making them private. Repeated code as I wanted to drill three layers deep. jQuery and $ detection for those that use it (I don't). For the device I was using the indentation is fine, you can modify it to suit your needs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.