43

Is there a way to find out all user defined window properties and variables (global variables) in javascript?

I tried console.log(window) but the list is endless.

hippietrail
  • 13,703
  • 15
  • 87
  • 133
GriffLab
  • 1,866
  • 3
  • 16
  • 21
  • Related (if not duplicate): [Fetching all (javascript) global variables in a page](http://stackoverflow.com/q/2226007/1048572), [Javascript - dumping all global variables](http://stackoverflow.com/q/8369338/1048572) – Bergi Jul 18 '14 at 09:29
  • @Bergi: Which answer here covers my question that was just marked as a dupe of this? Are you saying the question is a dupe even though the answers are not. Should the answer about `keys()` be moved from my question or are you saying that one's wrong and even though the answers here look outdated one of these is the right answer?? – hippietrail Apr 26 '15 at 11:57
  • @hippietrail: I don't see why the answers here would be outdated. (How) don't they work for you? It seems to be just what you want, if I didn't misunderstood your question. – Bergi Apr 26 '15 at 12:04

5 Answers5

101

You could also compare the window against a clean version of the window instead of trying to snapshot during runtime to compare against. I ran this in console but, you could turn it into a function.

// make sure it doesn't count my own properties
(function () {
    var results, currentWindow,
    // create an iframe and append to body to load a clean window object
    iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    // get the current list of properties on window
    currentWindow = Object.getOwnPropertyNames(window);
    // filter the list against the properties that exist in the clean window
    results = currentWindow.filter(function(prop) {
        return !iframe.contentWindow.hasOwnProperty(prop);
    });
    // log an array of properties that are different
    console.log(results);
    document.body.removeChild(iframe);
}());
jungy
  • 2,512
  • 1
  • 15
  • 17
  • 7
    Woah. That's exactly what I expected the answers to this question to be! Finally I can conveniently poke around in other people's code :) – Moritz Friedrich May 24 '17 at 10:03
  • Chrome's console doesn't log `results` properly as of nov. 18, I had to make `results` global then log it. Awesome code though! – Bigood Nov 08 '18 at 10:43
8

You would need to do the work for yourself. Read in all properties, on the first possible time you can. From that point on, you can compare the property list with your static one.

var globalProps = [ ];

function readGlobalProps() {
    globalProps = Object.getOwnPropertyNames( window );
}

function findNewEntries() {
    var currentPropList = Object.getOwnPropertyNames( window );

    return currentPropList.filter( findDuplicate );

    function findDuplicate( propName ) {
        return globalProps.indexOf( propName ) === -1;
    }
}

So now, we could go like

// on init
readGlobalProps();  // store current properties on global object

and later

window.foobar = 42;

findNewEntries(); // returns an array of new properties, in this case ['foobar']

Of course, the caveat here is, that you can only "freeze" the global property list at the time where your script is able to call it the earliest time.

jAndy
  • 212,463
  • 51
  • 293
  • 348
  • 1
    I think this would be the closest to a perfect answer . – andlrc Jun 22 '13 at 01:09
  • But maybe you should mention that `Object.getOwnPropertyNames` is part of the ECMAScript 5 Edition. Also filter and Array.indexOf – andlrc Jun 22 '13 at 01:11
  • 1
    @NULL well, I was used to mention it for the last couple of month, I feel its time to move on :) – jAndy Jun 22 '13 at 01:11
  • @jAndy definetely time to move on, I only support ie9 and above now, this is a brilliant answer thanks alot. – GriffLab Jun 22 '13 at 01:24
  • @jAndy maybe put the `readGlobalProps` in an IIFE that way it would be called as soon as you define it? – GriffLab Jun 22 '13 at 01:27
  • @GriffLab Yes. I guess the same way assuming that people don't worry about legacy browsers, I'm assuming they put their application logic in closured, private scopes :-) – jAndy Jun 22 '13 at 08:49
  • Does `keys(window)` not take care of most of the filtering? – hippietrail Apr 26 '15 at 12:01
  • This won't be any use from a userscript (Greasemonkey, Tapermonkey) since I don't believe userscript are guaranteed to run before the js in the page. What would the second best method be for that case? – hippietrail Apr 26 '15 at 12:23
  • @hippietrail *Since you don't believe, nothing will ever be...?* Believe me there's more out there, the Greasemonkey [`@run-at`](https://wiki.greasespot.net/Metadata_Block#.40run-at) for example. – yckart May 28 '17 at 07:52
8

This is in the same spirit as @jungy 's answer but we can do it in 3 lines:

document.body.appendChild(document.createElement('div')).innerHTML='<iframe id="temoin" style="display:none"></iframe>';

for (a in window) if (!(a in window.frames[window.frames.length-1])) console.log(a, window[a])

document.body.removeChild($$('#temoin')[0].parentNode);

First we add a hidden iframe; then we test existing variables against the standard JavaScript API in the iframe; then we remove the iframe.

To work more conveniently, it could be useful to sort the results in alphabetical order, and it's still possible in a 3 lines version:

document.body.appendChild(document.createElement('div')).innerHTML='<iframe id="temoin" style="display:none"></iframe>';

Object.keys(window).filter(a => !(a in window.frames[window.frames.length-1])).sort().forEach((a,i) => console.log(i, a, window[a]));

document.body.removeChild($$('#temoin')[0].parentNode);

And it can be packed into a bookmark:

javascript:document.body.appendChild(document.createElement('div')).innerHTML='<iframe%20id="temoin"%20style="display:none"></iframe>';Object.keys(window).filter(a=>!(a%20in%20window.frames[window.frames.length-1])).sort().forEach((a,i)=>console.log(i,a,window[a]));document.body.removeChild(document.querySelectorAll('#temoin')[0].parentNode);throw 'done';
Siltaar
  • 133
  • 1
  • 6
  • "it could be useful to sort the results in chronological order, and it's still possible in a 3 lines version: ..." Don't you mean alphabetical order? (chronological would mean based on time, not alphabetical/lexical sort) – Venryx Jun 03 '19 at 21:31
  • True, fixed. Thanks. – Siltaar Jun 05 '19 at 12:03
1

I ran this in the console in ChromeDev tool and it copied all of the user defined proper

function getUserDefinedKeys() {
    const globalKeys = ["postMessage","blur","focus","close","parent","opener","top","length","frames","closed","location","self","window","document","name","customElements","history","locationbar","menubar","personalbar","scrollbars","statusbar","toolbar","status","frameElement","navigator","origin","external","screen","innerWidth","innerHeight","scrollX","pageXOffset","scrollY","pageYOffset","visualViewport","screenX","screenY","outerWidth","outerHeight","devicePixelRatio","clientInformation","screenLeft","screenTop","defaultStatus","defaultstatus","styleMedia","onanimationend","onanimationiteration","onanimationstart","onsearch","ontransitionend","onwebkitanimationend","onwebkitanimationiteration","onwebkitanimationstart","onwebkittransitionend","isSecureContext","onabort","onblur","oncancel","oncanplay","oncanplaythrough","onchange","onclick","onclose","oncontextmenu","oncuechange","ondblclick","ondrag","ondragend","ondragenter","ondragleave","ondragover","ondragstart","ondrop","ondurationchange","onemptied","onended","onerror","onfocus","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","onseeked","onseeking","onselect","onstalled","onsubmit","onsuspend","ontimeupdate","ontoggle","onvolumechange","onwaiting","onwheel","onauxclick","ongotpointercapture","onlostpointercapture","onpointerdown","onpointermove","onpointerup","onpointercancel","onpointerover","onpointerout","onpointerenter","onpointerleave","onselectstart","onselectionchange","onafterprint","onbeforeprint","onbeforeunload","onhashchange","onlanguagechange","onmessage","onmessageerror","onoffline","ononline","onpagehide","onpageshow","onpopstate","onrejectionhandled","onstorage","onunhandledrejection","onunload","performance","stop","open","alert","confirm","prompt","print","queueMicrotask","requestAnimationFrame","cancelAnimationFrame","captureEvents","releaseEvents","requestIdleCallback","cancelIdleCallback","getComputedStyle","matchMedia","moveTo","moveBy","resizeTo","resizeBy","scroll","scrollTo","scrollBy","getSelection","find","webkitRequestAnimationFrame","webkitCancelAnimationFrame","fetch","btoa","atob","setTimeout","clearTimeout","setInterval","clearInterval","createImageBitmap","onappinstalled","onbeforeinstallprompt","crypto","indexedDB","webkitStorageInfo","sessionStorage","localStorage","chrome","onformdata","onpointerrawupdate","speechSynthesis","webkitRequestFileSystem","webkitResolveLocalFileSystemURL","openDatabase","applicationCache","caches","ondevicemotion","ondeviceorientation","ondeviceorientationabsolute","WebUIListener","cr","assert","assertNotReached","assertInstanceof","$","getSVGElement","getDeepActiveElement","findAncestorByClass","findAncestor","disableTextSelectAndDrag","isRTL","getRequiredElement","queryRequiredElement","appendParam","createElementWithClassName","ensureTransitionEndEvent","scrollTopForDocument","setScrollTopForDocument","scrollLeftForDocument","setScrollLeftForDocument","HTMLEscape","elide","quoteString","listenOnce","hasKeyModifiers","isTextInputElement"];
    return Object.fromEntries(Object.entries(window).filter(([key]) => !globalKeys.includes(key)));
}


const getCircularReplacer = () => {
  const seen = new WeakSet();
  return (key, value) => {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) {
        return;
      }
      seen.add(value);
    }
    return value;
  };
};

copy(JSON.stringify(getUserDefinedKeys(), getCircularReplacer()));
Raza
  • 1,971
  • 2
  • 23
  • 26
  • If your page has iframes and throws the following error, try launching chrome with the `--disable-web-security` flag: "Blocked a frame with origin "" from accessing a cross-origin frame." – Trent Aug 28 '20 at 17:14
-6

Maybe this?:

for (var property in window)
{
    if (window.hasOwnProperty(property))
        console.log(property)
}
LonelyWebCrawler
  • 2,724
  • 4
  • 33
  • 55